Compare commits

...

132 Commits

Author SHA1 Message Date
Michael K. Borregaard 92672ffddf Update news.md 2017-08-09 08:10:04 +02:00
Michael Krabbe Borregaard 2ccfa9b4fa Merge pull request #1001 from mkborregaard/mkb-release
disable precompilation for release
2017-08-09 08:05:45 +02:00
Michael K. Borregaard 1f07be6ae0 disable precompilation for release 2017-08-09 08:05:21 +02:00
Michael Krabbe Borregaard 9a8c7b290f Merge pull request #1000 from mkborregaard/fix-993
Move when output is included
2017-08-09 08:03:41 +02:00
Michael K. Borregaard 2e3bc15d2b Move when output is included 2017-08-08 20:24:17 +02:00
Michael Krabbe Borregaard 5e5412887c Merge pull request #989 from mkborregaard/fix-markershape-recipes
RFC: fix markershape in recipes
2017-07-29 08:51:51 +02:00
Josef Heinen b2efd5150b Merge pull request #992 from jheinen/master
gr: improved calculation of bottom margin
2017-07-28 05:37:09 -05:00
Josef Heinen 50ec31a7a3 gr: improved calculation of bottom margin 2017-07-28 12:17:47 +02:00
Daniel Schwabeneder 20bd9d6160 Merge pull request #988 from stevengj/nopywrap
don't use pywrap
2017-07-28 10:11:30 +02:00
Steven G. Johnson d0070c72fd whoops, forgot to commit these pywrap fixes 2017-07-27 14:15:48 -04:00
Michael K. Borregaard 780f3c49e9 Add test for markershape 2017-07-27 16:37:55 +02:00
Steven G. Johnson 2c191dbdbf don't use pywrap (closes #983) 2017-07-26 16:34:03 -04:00
Daniel Schwabeneder 4b617f96a3 Merge pull request #987 from daschw/ds-precompile
reactivate precompilation
2017-07-26 15:43:47 +02:00
Daniel Schwabeneder dabc3f998b reactivate precompilation 2017-07-26 15:14:07 +02:00
Daniel Schwabeneder 23a22102c5 Merge pull request #986 from daschw/ds-release
prepare v0.12.1 release
2017-07-26 15:09:33 +02:00
Daniel Schwabeneder 8d9ff7af11 prepare v0.12.1 release 2017-07-26 14:50:57 +02:00
Josef Heinen fdcb6086d1 Merge pull request #985 from jheinen/master
gr: fixed padding for guides
2017-07-26 03:02:03 -05:00
Josef Heinen 00e05efd7c gr: fixed padding for guides 2017-07-26 09:44:34 +02:00
Daniel Schwabeneder 0dd5eef3f2 Merge pull request #982 from daschw/ds-old-matplotlib
Allow Matplotlib 1.5 usage (fix #978)
2017-07-25 18:46:39 +02:00
Daniel Schwabeneder 6ecd30d42b warning --> warn 2017-07-24 14:55:28 +02:00
Daniel Schwabeneder 317091639f Merge pull request #977 from daschw/ds-plotly-surf
allow setting surface alpha in plotly(js) (fix #957)
2017-07-24 10:05:24 +02:00
Daniel Schwabeneder 9c8e879465 Merge pull request #976 from daschw/ds-gr-legend
Line legend marker for ribbons in GR (fix #896)
2017-07-24 10:03:57 +02:00
Daniel Schwabeneder dc5a04346a Merge pull request #975 from daschw/ds-tests
drop FactCheck in tests (fix #915)
2017-07-24 10:03:25 +02:00
Daniel Schwabeneder 44b533f501 allow matplotlib 1.5 usage 2017-07-24 10:02:44 +02:00
Daniel Schwabeneder 0fa459d590 fix alpha in legend markers 2017-07-21 10:52:36 +02:00
Daniel Schwabeneder 96d34bb5ee changed marker for path with fillrange 2017-07-21 10:05:27 +02:00
Daniel Schwabeneder 9f712b44f3 add ribbon area to marker 2017-07-21 09:12:27 +02:00
Daniel Schwabeneder 1ff8663e44 allow setting surface alpha in plotly 2017-07-21 01:12:39 +02:00
Daniel Schwabeneder 52f042263b fix case 2017-07-20 23:38:16 +02:00
Daniel Schwabeneder da7e57989c drop FactCheck and Glob in test/REQUIRE 2017-07-20 22:55:05 +02:00
Daniel Schwabeneder 65c3d90642 Merge pull request #971 from timholy/pull-request/a7a447a8
Update to newer Images
2017-07-20 22:23:52 +02:00
Daniel Schwabeneder 3c044d729d Merge pull request #970 from JuliaPlots/sd/glvisualize
fix glvisualize backend for 0.6
2017-07-20 22:20:34 +02:00
Daniel Schwabeneder 82ecf894c0 fix issues - replace at-fact with at-test 2017-07-20 21:50:06 +02:00
Daniel Schwabeneder 7b15f7d74b fix round() deprecation in gr.jl 2017-07-20 16:08:45 +02:00
Daniel Schwabeneder 371406845c drop Glob (enable testing on Windows) 2017-07-20 13:43:58 +02:00
Daniel Schwabeneder ccd26a6d42 drop FactCheck in tests 2017-07-20 13:25:09 +02:00
SimonDanisch e992930ff6 add contour as a dependency 2017-07-20 10:38:06 +02:00
SimonDanisch f66d8bed8f fix glvisualize backend for 0.6 2017-07-20 10:37:48 +02:00
Daniel Schwabeneder 155634ef34 change gr legend marker for ribbon 2017-07-19 21:26:25 +02:00
Josef Heinen dbc7bc4253 Merge pull request #940 from daschw/ds-heatmap-logscale
Avoid non-positive heatmap edges for log axis on GR and PyPlot
2017-07-18 01:22:26 -05:00
Daniel Schwabeneder fc427e618a Merge pull request #916 from pfitzseb/sp/juno
WIP: Better Juno integration
2017-07-17 20:40:48 +02:00
Sebastian Pfitzner 6d66190644 no eval shenanigans 2017-07-17 15:16:20 +02:00
Daniel Schwabeneder 9b2da0d645 Merge branch 'master' into ds-heatmap-logscale 2017-07-16 12:51:33 +02:00
Sebastian Pfitzner 95c60b9554 unrecursify this definition 2017-07-15 12:01:00 +02:00
Sebastian Pfitzner bc7f6a6fac circumvent warnings 2017-07-15 11:40:11 +02:00
Daniel Schwabeneder 0b1118540a Merge pull request #969 from pearlzli/plotly-fill
Add fillrange for Plotly backend
2017-07-14 22:55:33 +02:00
Tim Holy 96bd0bb46c Fix some errors/depwarns 2017-07-14 10:09:30 -05:00
Tim Holy 33e97ee49b Update to newer Images 2017-07-14 10:07:58 -05:00
Daniel Schwabeneder 8414facde2 Merge pull request #967 from JackDevine/fix-pyplot-deprecation
Fixed a deprecation warning on the pyplot backend
2017-07-13 09:33:25 +02:00
Pearl Li 2a0d5a0a03 Hide legend entry for series being filled to 2017-07-12 17:04:19 -04:00
Pearl Li aec30301a1 Add fillrange for Plotly 2017-07-12 16:20:53 -04:00
Sebastian Pfitzner 9cf246a03e fix juno plot sizing fallback 2017-07-12 10:40:26 +02:00
Sebastian Pfitzner c385035ac5 handle ijulia with requires
and properly check if juno/ijulia are actually used and not just loaded
2017-07-12 10:38:15 +02:00
JackDevine 409cf2c630 Fixed a deprecation warning on the pyplot backend
The follwing code created a deprecation warining:
using Plots; pyplot()
plot([1,2,3,4], [2,3,4,5], yscale=:log10)
2017-07-12 17:37:37 +12:00
SimonDanisch 02ddbc8381 fix glvisualize backend for 0.6 2017-07-11 09:04:35 +02:00
Daniel Schwabeneder 1c2a588864 Merge pull request #965 from rdeits/staticarrays
Switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
2017-07-10 13:47:49 +02:00
Robin Deits de043eeaa2 switch from FixedSizeArrays to StaticArrays.FixedSizeArrays 2017-07-05 17:12:39 -04:00
Sebastian Pfitzner 5e5f23b5e5 fix world age error 2017-07-02 20:56:04 +02:00
Sebastian Pfitzner d671ccd6ba better juno integration 2017-07-02 20:56:04 +02:00
Daniel Schwabeneder f4f2f09d17 Merge pull request #955 from albi3ro/master
fixing deprecation warning
2017-06-28 21:04:04 +02:00
Christina Lee 2f1c70e49f fixing deprecation warning 2017-06-28 11:42:16 -07:00
Josef Heinen d9890498d1 Merge pull request #951 from jheinen/master
gr: implemented "old" heatmap behaviour
2017-06-23 00:52:04 +02:00
Josef Heinen 46ae505bab gr: implemented "old" heatmap behaviour 2017-06-22 15:31:13 -07:00
Josef Heinen b0e84a68d0 Merge pull request #949 from jheinen/master
gr: fixed heatmap bug
2017-06-22 21:58:37 +02:00
Josef Heinen 356a5b6136 gr: fixed heatmap bug 2017-06-22 12:56:41 -07:00
Daniel Schwabeneder e86193cebe Merge pull request #947 from daschw/ds-datetime
Replace deprecated DateTime convert methods
2017-06-22 20:51:50 +02:00
Daniel Schwabeneder e35b2ec3ff replace deprecated DateTime convert methods 2017-06-22 18:51:03 +02:00
Josef Heinen 69d421d785 Merge pull request #944 from jheinen/master
gr: heatmaps now respect xlim/ylim specifications
2017-06-20 03:34:04 +02:00
Josef Heinen 47c51b28c1 gr: heatmaps now respect xlim/ylim specifications
Fixes https://github.com/JuliaPlots/Plots.jl/issues/942
2017-06-19 18:15:33 -07:00
Daniel Schwabeneder dd2653968e Merge pull request #941 from daschw/ds-plotlyjs-colorbar
Allow turning off the colorbar for heatmap, contour and surface on Plotly and PlotlyJS (fix #932)
2017-06-19 20:04:22 +02:00
Daniel Schwabeneder b091d95eb2 turn off colorbar for wireframe 2017-06-18 17:56:47 +02:00
Daniel Schwabeneder 33327d3992 allow turning off the colorbar for heatmap, contour and surface 2017-06-18 17:45:20 +02:00
Daniel Schwabeneder 027ce58655 avoid negative heatmap edges for log axis on gr and pyplot 2017-06-18 16:14:44 +02:00
Daniel Schwabeneder cd611ef4bf Merge pull request #939 from daschw/ds-tests
changed wkhtmltox link for tests
2017-06-18 16:10:25 +02:00
Daniel Schwabeneder bc7f5118ea changed package name for dpkg 2017-06-18 15:51:24 +02:00
Daniel Schwabeneder 53ae915044 changed wkhtmltox link 2017-06-18 11:59:27 +02:00
Michael Krabbe Borregaard a47f14ec13 Merge pull request #936 from ma-laforge/inspectdr
Conform to changes in InspectDR.PlotLayout.
2017-06-18 08:00:09 +02:00
MA Laforge 86149ba3a7 Conform to changes in InspectDR.PlotLayout. 2017-06-16 17:17:01 -04:00
Michael Krabbe Borregaard cc3822b222 Merge pull request #933 from sbromberger/patch-1
Update output.jl
2017-06-16 17:21:26 +02:00
Seth Bromberger 57b9602b13 Update output.jl
Change `readall` to `readstring` for 0.6- compatibility.
2017-06-15 20:12:26 -07:00
Daniel Schwabeneder c9839dbefa Merge pull request #926 from daschw/ds-pyplot-colorbar
Reduced colorbar size on PyPlot for big z values (fix #925)
2017-06-13 18:48:48 +02:00
Daniel Schwabeneder 5b6423ec6c only change top corners of colorbar axes 2017-06-12 22:15:57 +02:00
Daniel Schwabeneder b3efcf9b68 reduced colorbar size for z axis limits >= 1e7 2017-06-12 20:39:49 +02:00
Michael Krabbe Borregaard cadb0f96e2 Merge pull request #837 from floswald/reset
resetfontsizes: fixes #836
2017-06-12 13:31:55 +02:00
florian oswald d3b825b49f fix docstrings. provide 2 methods scalefontsizes now, with and without an argument. no argument version resets to initial values, with argument you rescale the current sizes. 2017-06-12 12:29:19 +02:00
Michael K. Borregaard c808cbb4fa restore precompilation 2017-06-11 22:28:07 +02:00
Michael Krabbe Borregaard 228d3af1fa Merge pull request #922 from mkborregaard/make-tkelman-happy
remove all 0.5-compliant uses of the transpose operator
2017-06-11 22:26:53 +02:00
Michael K. Borregaard a1df325051 Remove all 0.5-compliant uses of the transpose operator (')
A horrible change, but one required by the metadata maintainers.
2017-06-11 22:25:15 +02:00
Daniel Schwabeneder 8e6fdfac3c Merge pull request #921 from daschw/ds-precompile
reactivate precompilation on master
2017-06-10 23:36:57 +02:00
Daniel Schwabeneder 9a1afb2376 reactivate precompilation 2017-06-10 23:13:03 +02:00
Michael K. Borregaard e9ab8c4dac require RecipesBase 0.2.0 2017-06-09 22:57:23 +02:00
Michael Krabbe Borregaard 1d98acc407 deactivate precompilation for release 2017-06-09 22:04:48 +02:00
Michael Krabbe Borregaard 034613b50c Merge pull request #804 from ChrisRackauckas/_cycle
Change cycle => _cycle
2017-06-09 20:09:26 +02:00
Michael Krabbe Borregaard 282e611ef7 Merge pull request #803 from ChrisRackauckas/recipes_change
RecipesBase change: all recipes usable from RecipesBase
2017-06-09 20:09:15 +02:00
ChrisRackauckas 49fc903334 fix last cycle 2017-06-09 08:43:01 -07:00
ChrisRackauckas 44b6157f17 cycle => _cycle 2017-06-09 08:43:01 -07:00
ChrisRackauckas 0a8d3f9251 animate from RecipesBase 2017-06-09 08:42:00 -07:00
ChrisRackauckas ac505ede44 move abstract types and make PlotRecipe on abstract type 2017-06-09 08:42:00 -07:00
ChrisRackauckas 4770f8b580 Merge remote-tracking branch 'ChrisRackauckas/master' into patch-1 2017-06-09 08:41:26 -07:00
Christopher Rackauckas 67e5598d28 Move the @userplot recipes
https://github.com/JuliaPlots/RecipesBase.jl/pull/16
2017-06-09 08:41:26 -07:00
ChrisRackauckas 554d7ab887 remove @shorthands 2017-06-09 08:41:26 -07:00
Michael K. Borregaard 40734bf90e Revert "turn off precompilation for release"
This reverts commit 66d9c79bef.
2017-06-09 16:00:39 +02:00
Michael Krabbe Borregaard 3e720f8bae Merge pull request #919 from mkborregaard/ready-for-release
turn off precompilation for release
2017-06-09 15:58:38 +02:00
Michael K. Borregaard 66d9c79bef turn off precompilation for release 2017-06-09 15:58:09 +02:00
Michael Krabbe Borregaard 89a5e5d57a Merge pull request #914 from mkborregaard/change-ignorenan-case
ignoreNaN => ignorenan
2017-06-08 12:54:47 +02:00
Michael K. Borregaard 8f6b0c50d6 ignoreNaN => ignorenan 2017-06-08 12:54:25 +02:00
Michael Krabbe Borregaard d85dfaf38a Merge pull request #913 from mkborregaard/fix-broadcast
update Base..* to 0.6 syntax
2017-06-08 11:13:08 +02:00
Michael K. Borregaard 8511152982 update Base..* to 0.6 syntax 2017-06-08 10:56:12 +02:00
Michael Krabbe Borregaard 40f9a51d4f Merge pull request #909 from mkborregaard/reactivate-precompilation
reactivate precompilation
2017-06-08 10:47:56 +02:00
Daniel Schwabeneder 30ad6d93bc Merge pull request #908 from daschw/ds-tests-2
Make tests pass on 0.6 2
2017-06-08 10:27:04 +02:00
Josef Heinen 770d907fb8 Merge pull request #910 from jheinen/master
gr: removed println statement
2017-06-07 18:18:11 -07:00
Josef Heinen 46cdbacf0b gr: removed println statement 2017-06-07 18:15:43 -07:00
Michael K. Borregaard c0a8adc167 reactivate precompilation 2017-06-08 00:55:23 +02:00
Daniel Schwabeneder 4dd176a7f2 add @eval in image_comparision_tests and replaced transpose in testexample 13 2017-06-08 00:19:36 +02:00
Michael Krabbe Borregaard eac9023b9a Merge pull request #904 from mkborregaard/Change-test-versions-to-release
Use ImageMagick release
2017-06-08 00:09:41 +02:00
Michael Krabbe Borregaard a4c403286d Merge pull request #906 from mkborregaard/change-to-0.6
Up requirement to julia 0.6
2017-06-07 23:59:21 +02:00
Michael K. Borregaard 3a2ee0fc72 Fix some deprecations 2017-06-07 23:55:30 +02:00
Michael K. Borregaard f097fb57b5 Fix some deprecation warnings 2017-06-07 23:55:30 +02:00
Michael K. Borregaard 7415a362c4 reactivate precompilation 2017-06-07 23:55:30 +02:00
Michael K. Borregaard 8a7b7f5c9b Up requirement to 0.6 2017-06-07 23:55:30 +02:00
Michael Krabbe Borregaard 4ce35ef352 Merge pull request #894 from mkborregaard/legendtitle_example
Adds legendtitle to example 12
2017-06-07 23:54:39 +02:00
Michael K. Borregaard a12f601b9c add legendtitle to example 2017-06-07 23:54:05 +02:00
Michael K. Borregaard 4106161aa8 add colon 2017-06-07 23:54:05 +02:00
Michael K. Borregaard 58c2f35bcf reinclude Plots 2017-06-07 23:54:05 +02:00
Michael K. Borregaard c41839a816 Add legendtitle to example 13 2017-06-07 23:54:05 +02:00
Michael K. Borregaard c7a13a4641 Use ImageMagick release 2017-06-07 16:54:24 +02:00
florian oswald 6cca763284 removed test for k 2017-05-17 21:07:54 +02:00
Florian Oswald 915c41c9d9 addressed changes requested 2017-05-17 17:48:03 +02:00
Florian Oswald 9c2c548874 create dict _initial_fontsizes and copy from that. creates new method scalefontsizes() [no keyword] 2017-05-17 17:10:21 +02:00
Florian Oswald fdf699bf35 added const copies of _all_defaults and _axis_defaults to be able to reset fonts to initial values with new resetfontsizes method 2017-05-17 16:34:03 +02:00
Florian Oswald e3ce1ab1d1 just calling default(k) does not give back the default value for k 2017-05-17 15:40:47 +02:00
Florian Oswald af56d6f265 added resetfontsizes() 2017-05-17 15:31:26 +02:00
29 changed files with 517 additions and 447 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ os:
- linux
# - osx
julia:
- 0.5
- 0.6
matrix:
allow_failures:
- julia: nightly
+26 -1
View File
@@ -9,8 +9,33 @@
- `backports` branch is for Julia 0.4
---
## (current master)
## 0.11 (current master/dev)
## 0.12.2
- fix an issue with Juno/PlotlyJS compatibility on new installations
- fix markers not showing up in seriesrecipes using :scatter
- don't use pywrap in the pyplot backend
- improve the bottom margin for the gr backend
## 0.12.1
- fix deprecation warnings
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
- drop FactCheck in tests
- remove julia 0.5 compliant uses of transpose operator
- fix GR heatmap bugs
- fix GR guide padding
- improve legend markers in GR
- add surface alpha for Plotly(JS)
- add fillrange to Plotly(JS)
- allow usage of Matplotlib 1.5 with PyPlot
- fix GLVisualize for julia 0.6
- conform to changes in InspectDR
#### 0.12.0
- 0.6 only
#### 0.11.3
+5 -3
View File
@@ -1,13 +1,15 @@
julia 0.5
julia 0.6-pre
RecipesBase
RecipesBase 0.2.0
PlotUtils 0.4.1
PlotThemes 0.1.3
Reexport
FixedSizeArrays
StaticArrays 0.5
FixedPointNumbers 0.3
Measures
Showoff
StatsBase 0.14.0
JSON
NaNMath
Requires
Contour
+28 -28
View File
@@ -3,8 +3,12 @@ __precompile__(false)
module Plots
using Reexport
using FixedSizeArrays
import StaticArrays
using StaticArrays.FixedSizeArrays
@reexport using RecipesBase
import RecipesBase: plot, animate
using Base.Meta
@reexport using PlotUtils
@reexport using PlotThemes
@@ -30,9 +34,6 @@ export
with,
twinx,
@userplot,
@shorthands,
pie,
pie!,
plot3d,
@@ -107,14 +108,26 @@ 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)
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)
# ---------------------------------------------------------
# to cater for block matrices, Base.transpose is recursive.
# This makes it impossible to create row vectors of String and Symbol with the transpose operator.
# This solves this issue, internally in Plots at least.
# commented out on the insistence of the METADATA maintainers
#Base.transpose(x::Symbol) = x
#Base.transpose(x::String) = x
# ---------------------------------------------------------
@@ -138,25 +151,14 @@ include("layouts.jl")
include("subplots.jl")
include("recipes.jl")
include("animation.jl")
include("output.jl")
include("examples.jl")
include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
include("output.jl")
# ---------------------------------------------------------
# define and export shorthand plotting method definitions
macro shorthands(funcname::Symbol)
funcname2 = Symbol(funcname, "!")
esc(quote
export $funcname, $funcname2
$funcname(args...; kw...) = plot(args...; kw..., seriestype = $(quot(funcname)))
$funcname2(args...; kw...) = plot!(args...; kw..., seriestype = $(quot(funcname)))
end)
end
@shorthands scatter
@shorthands bar
@shorthands barh
@@ -241,10 +243,8 @@ end
const CURRENT_BACKEND = CurrentBackend(:none)
function __init__()
setup_ijulia()
setup_atom()
# for compatibility with Requires.jl:
@init begin
if isdefined(Main, :PLOTS_DEFAULTS)
for (k,v) in Main.PLOTS_DEFAULTS
default(k, v)
+9 -1
View File
@@ -336,6 +336,12 @@ const _all_defaults = KW[
_axis_defaults_byletter
]
# to be able to reset font sizes to initial values
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefont].pointsize,
:legendfont => _subplot_defaults[:legendfont].pointsize,
:tickfont => _axis_defaults[:tickfont].pointsize,
:guidefont => _axis_defaults[:guidefont].pointsize)
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
@@ -522,7 +528,6 @@ function default(d::KW, k::Symbol)
end
# -----------------------------------------------------------------------------
# if arg is a valid color value, then set d[csym] and return true
@@ -701,6 +706,9 @@ function preprocessArgs!(d::KW)
delete!(d, :marker)
if haskey(d, :markershape)
d[:markershape] = _replace_markershape(d[:markershape])
if d[:markershape] == :none && d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
d[:markershape] = :circle
end
elseif anymarker
d[:markershape_to_add] = :circle # add it after _apply_recipe
end
+4 -4
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))
ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
const _scale_funcs = Dict{Symbol,Function}(
@@ -349,11 +349,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] = ignorenan_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, ignorenan_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end
end
+38 -45
View File
@@ -58,7 +58,7 @@ const _glvisualize_scale = [:identity, :ln, :log2, :log10]
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval begin
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
import FileIO, Images
export GLVisualize
import Reactive: Signal
@@ -66,9 +66,8 @@ function _initialize_backend(::GLVisualizeBackend; kw...)
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
Plots.slice_arg(img::Images.AbstractImage, idx::Int) = img
Plots.slice_arg{C<:Colorant}(img::Matrix{C}, idx::Int) = img
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported{Img<:Images.AbstractImage}(::GLVisualizeBackend, shape::Union{Vector{Img}, Img}) = true
is_marker_supported{C<:Colorant}(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
const GL = Plots
@@ -173,12 +172,12 @@ function gl_marker(shape)
shape
end
function gl_marker(shape::Shape)
points = Point2f0[Vec{2,Float32}(p) for p in zip(shape.x, shape.y)]
points = Point2f0[GeometryTypes.Vec{2, Float32}(p) for p in zip(shape.x, shape.y)]
bb = GeometryTypes.AABB(points)
mini, maxi = minimum(bb), maximum(bb)
w3 = maxi-mini
origin, width = Point2f0(mini[1], mini[2]), Point2f0(w3[1], w3[2])
map!(p -> ((p - origin) ./ width) - 0.5f0, points) # normalize and center
map!(p -> ((p - origin) ./ width) - 0.5f0, points, points) # normalize and center
GeometryTypes.GLNormalMesh(points)
end
# create a marker/shape type
@@ -212,13 +211,13 @@ function extract_limits(sp, d, kw_args)
nothing
end
to_vec{T <: FixedVector}(::Type{T}, vec::T) = vec
to_vec{T <: FixedVector}(::Type{T}, s::Number) = T(s)
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vec::T) = vec
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, s::Number) = T(s)
to_vec{T <: FixedVector{2}}(::Type{T}, vec::FixedVector{3}) = T(vec[1], vec[2])
to_vec{T <: FixedVector{3}}(::Type{T}, vec::FixedVector{2}) = T(vec[1], vec[2], 0)
to_vec{T <: StaticArrays.StaticVector{2}}(::Type{T}, vec::StaticArrays.StaticVector{3}) = T(vec[1], vec[2])
to_vec{T <: StaticArrays.StaticVector{3}}(::Type{T}, vec::StaticArrays.StaticVector{2}) = T(vec[1], vec[2], 0)
to_vec{T <: FixedVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
function extract_marker(d, kw_args)
dim = Plots.is3d(d) ? 3 : 2
@@ -274,7 +273,7 @@ function extract_surface(d)
map(_extract_surface, (d[:x], d[:y], d[:z]))
end
function topoints{P}(::Type{P}, array)
P[x for x in zip(array...)]
[P(x) for x in zip(array...)]
end
function extract_points(d)
dim = is3d(d) ? 3 : 2
@@ -304,7 +303,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(ignorenan_extrema(d[:y]))
end
end
else
@@ -315,7 +314,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(ignorenan_extrema(d[:y]))
else
error("Unsupported limits: $clims")
end
@@ -482,7 +481,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 = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
nothing
end
@@ -509,7 +508,7 @@ function extract_colornorm(d, kw_args)
else
d[:y]
end
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(z))
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(z))
kw_args[:intensity] = map(Float32, collect(z))
end
end
@@ -576,8 +575,10 @@ end
function align_offset(startpos, lastpos, atlas, rscale, font, align)
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
xmove = (lastpos-startpos)[1]+xscale
if align == :top
xmove = (lastpos-startpos)[1] + xscale
if isa(align, GeometryTypes.Vec)
return -Vec2f0(xmove, yscale) .* align
elseif align == :top
return -Vec2f0(xmove/2f0, yscale)
elseif align == :right
return -Vec2f0(xmove, yscale/2f0)
@@ -586,11 +587,6 @@ function align_offset(startpos, lastpos, atlas, rscale, font, align)
end
end
function align_offset(startpos, lastpos, atlas, rscale, font, align::Vec)
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
xmove = (lastpos-startpos)[1] + xscale
return -Vec2f0(xmove, yscale) .* align
end
function alignment2num(x::Symbol)
(x in (:hcenter, :vcenter)) && return 0.5
@@ -638,7 +634,7 @@ function draw_ticks(
position = GLVisualize.calc_position(str, startpos, sz, font, atlas)
offset = GLVisualize.calc_offset(str, sz, font, atlas)
alignoff = align_offset(startpos, last(position), atlas, sz, font, align)
map!(position) do pos
map!(position, position) do pos
pos .+ alignoff
end
append!(positions, position)
@@ -660,7 +656,7 @@ function glvisualize_text(position, text, kw_args)
offset = GLVisualize.calc_offset(text.str, rscale, font, atlas)
alignoff = align_offset(startpos, last(position), atlas, rscale, font, text_align)
map!(position) do pos
map!(position, position) do pos
pos .+ alignoff
end
kw_args[:position] = position
@@ -781,9 +777,9 @@ function gl_bar(d, kw_args)
# compute half-width of bars
bw = nothing
hw = if bw == nothing
ignoreNaN_mean(diff(x))
ignorenan_mean(diff(x))
else
Float64[cycle(bw,i)*0.5 for i=1:length(x)]
Float64[_cycle(bw,i)*0.5 for i=1:length(x)]
end
# make fillto a vector... default fills to 0
@@ -792,12 +788,12 @@ function gl_bar(d, kw_args)
fillto = 0
end
# create the bar shapes by adding x/y segments
positions, scales = Array(Point2f0, ny), Array(Vec2f0, ny)
positions, scales = Array{Point2f0}(ny), Array{Vec2f0}(ny)
m = Reactive.value(kw_args[:model])
sx, sy = m[1,1], m[2,2]
for i=1:ny
center = x[i]
hwi = abs(cycle(hw,i)); yi = y[i]; fi = cycle(fillto,i)
hwi = abs(_cycle(hw,i)); yi = y[i]; fi = _cycle(fillto,i)
if Plots.isvertical(d)
sz = (hwi*sx, yi*sy)
else
@@ -833,7 +829,7 @@ function gl_boxplot(d, kw_args)
sx, sy = m[1,1], m[2,2]
for (i,glabel) in enumerate(glabels)
# filter y
values = y[filter(i -> cycle(x,i) == glabel, 1:length(y))]
values = y[filter(i -> _cycle(x,i) == glabel, 1:length(y))]
# compute quantiles
q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5))
# notch
@@ -846,7 +842,7 @@ function gl_boxplot(d, kw_args)
# make the shape
center = Plots.discrete_value!(d[:subplot][:xaxis], glabel)[1]
hw = d[:bar_width] == nothing ? Plots._box_halfwidth*2 : cycle(d[:bar_width], i)
hw = d[:bar_width] == nothing ? Plots._box_halfwidth*2 : _cycle(d[:bar_width], i)
l, m, r = center - hw/2, center, center + hw/2
# internal nodes for notches
@@ -864,7 +860,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 = ignorenan_extrema(inside)
end
# Box
if notch
@@ -943,9 +939,9 @@ function scale_for_annotations!(series::Series, scaletype::Symbol = :pixels)
# we use baseshape to overwrite the markershape attribute
# with a list of custom shapes for each
msw, msh = anns.scalefactor
offsets = Array(Vec2f0, length(anns.strs))
offsets = Array{Vec2f0}(length(anns.strs))
series[:markersize] = map(1:length(anns.strs)) do i
str = cycle(anns.strs, i)
str = _cycle(anns.strs, i)
# get the width and height of the string (in mm)
sw, sh = text_size(str, anns.font.pointsize)
@@ -1058,7 +1054,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
kw = copy(kw_args)
fr = d[:fillrange]
ps = if all(x-> x >= 0, diff(d[:x])) # if is monotonic
vcat(points, Point2f0[(points[i][1], cycle(fr, i)) for i=length(points):-1:1])
vcat(points, Point2f0[(points[i][1], _cycle(fr, i)) for i=length(points):-1:1])
else
points
end
@@ -1122,7 +1118,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
anns = series[:series_annotations]
for (x, y, str, font) in EachAnn(anns, d[:x], d[:y])
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
x, y = Reactive.value(model_m) * Vec{4, Float32}(x, y, 0, 1)
x, y = Reactive.value(model_m) * GeometryTypes.Vec{4, Float32}(x, y, 0, 1)
extract_font(font, txt_args)
t = glvisualize_text(Point2f0(x, y), PlotText(str, font), txt_args)
GLVisualize._view(t, sp_screen, camera = :perspective)
@@ -1148,10 +1144,7 @@ function _show(io::IO, ::MIME"image/png", plt::Plot{GLVisualizeBackend})
GLWindow.render_frame(GLWindow.rootscreen(plt.o))
GLWindow.swapbuffers(plt.o)
buff = GLWindow.screenbuffer(plt.o)
png = Images.Image(map(RGB{U8}, buff),
colorspace = "sRGB",
spatialorder = ["y", "x"]
)
png = map(RGB{U8}, buff)
FileIO.save(FileIO.Stream(FileIO.DataFormat{:PNG}, io), png)
end
@@ -1231,7 +1224,7 @@ function gl_scatter(points, kw_args)
if haskey(kw_args, :stroke_width)
s = Reactive.value(kw_args[:scale])
sw = kw_args[:stroke_width]
if sw*5 > cycle(Reactive.value(s), 1)[1] # restrict marker stroke to 1/10th of scale (and handle arrays of scales)
if sw*5 > _cycle(Reactive.value(s), 1)[1] # restrict marker stroke to 1/10th of scale (and handle arrays of scales)
kw_args[:stroke_width] = s[1] / 5f0
end
end
@@ -1309,8 +1302,8 @@ function gl_contour(x, y, z, kw_args)
if kw_args[:fillrange] != nothing
delete!(kw_args, :intensity)
I = GLVisualize.Intensity{1, Float32}
main = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
I = GLVisualize.Intensity{Float32}
main = [I(z[j,i]) for i=1:size(z, 2), j=1:size(z, 1)]
return visualize(main, Style(:default), kw_args)
else
@@ -1318,7 +1311,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(ignorenan_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,10 +1332,10 @@ end
function gl_heatmap(x,y,z, kw_args)
get!(kw_args, :color_norm, Vec2f0(ignoreNaN_extrema(z)))
get!(kw_args, :color_norm, Vec2f0(ignorenan_extrema(z)))
get!(kw_args, :color_map, Plots.make_gradient(cgrad()))
delete!(kw_args, :intensity)
I = GLVisualize.Intensity{1, Float32}
I = GLVisualize.Intensity{Float32}
heatmap = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
tex = GLAbstraction.Texture(heatmap, minfilter=:nearest)
kw_args[:stroke_width] = 0f0
+75 -29
View File
@@ -124,10 +124,10 @@ function gr_getcolorind(c)
convert(Int, GR.inqcolorfromrgb(red(c), green(c), blue(c)))
end
gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(cycle(c,1)))
gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(cycle(c,1)))
gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(cycle(c,1)))
gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(cycle(c,1)))
gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(_cycle(c,1)))
gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c,1)))
gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(_cycle(c,1)))
gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(_cycle(c,1)))
# --------------------------------------------------------------------------------------
@@ -264,7 +264,7 @@ end
normalize_zvals(zv::Void) = zv
function normalize_zvals(zv::AVec)
vmin, vmax = ignoreNaN_extrema(zv)
vmin, vmax = ignorenan_extrema(zv)
if vmin == vmax
zeros(length(zv))
else
@@ -272,6 +272,10 @@ function normalize_zvals(zv::AVec)
end
end
gr_alpha(α::Void) = 1
gr_alpha(α::Real) = α
# ---------------------------------------------------------
# draw ONE Shape
@@ -301,23 +305,23 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
shapes = series[:markershape]
if shapes != :none
for i=1:length(x)
msi = cycle(msize, i)
shape = cycle(shapes, i)
msi = _cycle(msize, i)
shape = _cycle(shapes, i)
cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor
cfuncind = isa(shape, Shape) ? GR.setfillcolorind : GR.setmarkercolorind
# draw a filled in shape, slightly bigger, to estimate a stroke
if series[:markerstrokewidth] > 0
cfunc(cycle(series[:markerstrokecolor], i)) #, series[:markerstrokealpha])
cfunc(_cycle(series[:markerstrokecolor], i)) #, series[:markerstrokealpha])
gr_draw_marker(x[i], y[i], msi + series[:markerstrokewidth], shape)
end
# draw the shape
if mz == nothing
cfunc(cycle(series[:markercolor], i)) #, series[:markeralpha])
cfunc(_cycle(series[:markercolor], i)) #, series[:markeralpha])
else
# pick a color from the pre-loaded gradient
ci = round(Int, 1000 + cycle(mz, i) * 255)
ci = round(Int, 1000 + _cycle(mz, i) * 255)
cfuncind(ci)
GR.settransparency(_gr_gradient_alpha[ci-999])
end
@@ -353,7 +357,7 @@ function gr_set_fill(c) #, a)
end
# this stores the conversion from a font pointsize to "percentage of window height" (which is what GR uses)
const _gr_point_mult = zeros(1)
const _gr_point_mult = 0.0018 * ones(1)
# set the font attributes... assumes _gr_point_mult has been populated already
function gr_set_font(f::Font; halign = f.halign, valign = f.valign,
@@ -384,7 +388,7 @@ end
const viewport_plotarea = zeros(4)
# the size of the current plot in pixels
const gr_plot_size = zeros(2)
const gr_plot_size = [600.0, 400.0]
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
viewport = zeros(4)
@@ -448,7 +452,6 @@ gr_view_ycenter() = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4])
function gr_legend_pos(s::Symbol,w,h)
str = string(s)
println(str)
if str == "best"
str = "topright"
end
@@ -535,7 +538,35 @@ end
function _update_min_padding!(sp::Subplot{GRBackend})
sp.minpad = (10mm,2mm,2mm,8mm)
leftpad = 10mm
toppad = 2mm
rightpad = 2mm
bottompad = 6mm
if sp[:title] != ""
toppad += 5mm
end
if sp[:xaxis][:guide] != ""
xticks = axis_drawing_info(sp)[1]
if !(xticks in (nothing, false))
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = :top,
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation])
h = 0
for (cv, dv) in zip(xticks...)
tbx, tby = gr_inqtext(0, 0, string(dv))
h = max(h, tby[2] - tby[1])
end
bottompad += 1mm + gr_plot_size[2] * h * px
else
bottompad += 4mm
end
end
if sp[:yaxis][:guide] != ""
leftpad += 4mm
end
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
@@ -545,6 +576,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas)
# get data limits
data_lims = gr_xy_axislims(sp)
xy_lims = data_lims
ratio = sp[:aspect_ratio]
if ratio != :none
@@ -586,7 +618,8 @@ 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])
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale])
xy_lims = x[1], x[end], y[1], y[end]
expand_extrema!(sp[:xaxis], x)
expand_extrema!(sp[:yaxis], y)
data_lims = gr_xy_axislims(sp)
@@ -667,7 +700,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(ignorenan_minimum(r), ignorenan_maximum(r))
# rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax)
@@ -706,7 +739,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
rotation = sp[:xaxis][:rotation])
for (cv, dv) in zip(xticks...)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(cv, (flip $ mirror) ? ymax : ymin)
xi, yi = GR.wctondc(cv, xor(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))
end
@@ -723,7 +756,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
rotation = sp[:yaxis][:rotation])
for (cv, dv) in zip(yticks...)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc((flip $ mirror) ? xmax : xmin, cv)
xi, yi = GR.wctondc(xor(flip, mirror) ? xmax : xmin, cv)
# @show cv dv xmin xi yi
gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv))
end
@@ -809,9 +842,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
for (i,rng) in enumerate(iter_segments(series[:x], series[:y]))
if length(rng) > 1
gr_set_fillcolor(cycle(series[:fillcolor], i))
fx = cycle(x, vcat(rng, reverse(rng)))
fy = vcat(cycle(fr_from,rng), cycle(fr_to,reverse(rng)))
gr_set_fillcolor(_cycle(series[:fillcolor], i))
fx = _cycle(x, vcat(rng, reverse(rng)))
fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
# @show i rng fx fy
GR.fillarea(fx, fy)
end
@@ -852,7 +885,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 - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_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)
@@ -874,6 +907,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
cmap && gr_colorbar(sp)
elseif st == :heatmap
xmin, xmax, ymin, ymax = xy_lims
zmin, zmax = gr_lims(zaxis, true)
clims = sp[:clims]
if is_2tuple(clims)
@@ -887,7 +921,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
round(Int, blue(c) * 255) << 16 +
round(Int, green(c) * 255) << 8 +
round(Int, red(c) * 255) ), colors)
GR.drawimage(xmin, xmax, ymax, ymin, length(x), length(y), rgba)
w, h = length(x), length(y)
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
cmap && gr_colorbar(sp)
elseif st in (:path3d, :scatter3d)
@@ -963,11 +998,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
x, y = series[:x][rng], series[:y][rng]
# draw the interior
gr_set_fill(cycle(series[:fillcolor], i))
gr_set_fill(_cycle(series[:fillcolor], i))
GR.fillarea(x, y)
# draw the shapes
gr_set_line(series[:linewidth], :solid, cycle(series[:linecolor], i))
gr_set_line(series[:linewidth], :solid, _cycle(series[:linecolor], i))
GR.polyline(x, y)
end
end
@@ -1039,6 +1074,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if sp[:legendtitle] != nothing
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
gr_set_textcolor(sp[:foreground_color_legend])
GR.settransparency(1)
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
ypos -= dy
end
@@ -1046,16 +1082,26 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
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
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
elseif st == :shape || series[:fillrange] != nothing
if st == :shape || series[:fillrange] != nothing
gr_set_fill(series[:fillcolor]) #, series[:fillalpha])
l, r = xpos-0.07, xpos-0.01
b, t = ypos-0.4dy, ypos+0.4dy
x = [l, r, r, l, l]
y = [b, b, t, t, b]
GR.settransparency(gr_alpha(series[:fillalpha]))
gr_polyline(x, y, GR.fillarea)
gr_polyline(x, y)
GR.settransparency(gr_alpha(series[:linealpha]))
st == :shape && gr_polyline(x, y)
end
if st == :path
GR.settransparency(gr_alpha(series[:linealpha]))
if series[:fillrange] == nothing || series[:ribbon] != nothing
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
else
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos+0.4dy, ypos+0.4dy])
end
end
if series[:markershape] != :none
+22 -23
View File
@@ -265,8 +265,8 @@ For st in :shape:
nmax = i
if length(rng) > 1
linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(cycle(series[:linecolor], i))
fillcolor = _inspectdr_mapcolor(cycle(series[:fillcolor], i))
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
line = InspectDR.line(
style=:solid, width=linewidth, color=linecolor
)
@@ -280,8 +280,8 @@ For st in :shape:
i = (nmax >= 2? div(nmax, 2): nmax) #Must pick one set of colors for legend
if i > 1 #Add dummy waveform for legend entry:
linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(cycle(series[:linecolor], i))
fillcolor = _inspectdr_mapcolor(cycle(series[:fillcolor], i))
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
wfrm = InspectDR.add(plot, Float64[], Float64[], id=series[:label])
wfrm.line = InspectDR.line(
style=:none, width=linewidth, #linewidth affects glyph
@@ -362,30 +362,29 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
l = plot.layout
l.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l.framedata.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l.framedata.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l.fnttitle = InspectDR.Font(sp[:titlefont].family,
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l[:font_title] = InspectDR.Font(sp[:titlefont].family,
_inspectdr_mapptsize(sp[:titlefont].pointsize),
color = _inspectdr_mapcolor(sp[:foreground_color_title])
)
#Cannot independently control fonts of axes with InspectDR:
l.fntaxlabel = InspectDR.Font(xaxis[:guidefont].family,
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefont].family,
_inspectdr_mapptsize(xaxis[:guidefont].pointsize),
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide])
)
l.fntticklabel = InspectDR.Font(xaxis[:tickfont].family,
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfont].family,
_inspectdr_mapptsize(xaxis[:tickfont].pointsize),
color = _inspectdr_mapcolor(xaxis[:foreground_color_text])
)
leg = l.legend
leg.enabled = (sp[:legend] != :none)
#leg.width = 150 #TODO: compute???
leg.font = InspectDR.Font(sp[:legendfont].family,
l[:enable_legend] = (sp[:legend] != :none)
#l[:halloc_legend] = 150 #TODO: compute???
l[:font_legend] = InspectDR.Font(sp[:legendfont].family,
_inspectdr_mapptsize(sp[:legendfont].pointsize),
color = _inspectdr_mapcolor(sp[:foreground_color_legend])
)
leg.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
end
# called just before updating layout bounding boxes... in case you need to prep
@@ -399,7 +398,7 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
#Don't use window_title... probably not what you want.
#mplot.title = plt[:window_title]
end
mplot.frame.fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
resize!(mplot.subplots, length(plt.subplots))
nsubplots = length(plt.subplots)
@@ -421,15 +420,15 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
#Do not yet support absolute plot positionning.
#Just try to make things look more-or less ok:
if nsubplots <= 1
mplot.ncolumns = 1
mplot.layout[:ncolumns] = 1
elseif nsubplots <= 4
mplot.ncolumns = 2
mplot.layout[:ncolumns] = 2
elseif nsubplots <= 6
mplot.ncolumns = 3
mplot.layout[:ncolumns] = 3
elseif nsubplots <= 12
mplot.ncolumns = 4
mplot.layout[:ncolumns] = 4
else
mplot.ncolumns = 5
mplot.layout[:ncolumns] = 5
end
for series in plt.series_list
@@ -446,7 +445,7 @@ function _update_min_padding!(sp::Subplot{InspectDRBackend})
plot = sp.o
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
#Computing plotbounds with 0-BoundingBox returns required padding:
bb = InspectDR.plotbounds(plot.layout, InspectDR.BoundingBox(0,0,0,0))
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
#TODO: possibly zero-out items not in use??
@@ -468,7 +467,7 @@ function _update_plot_object(plt::Plot{InspectDRBackend})
for (i, sp) in enumerate(plt.subplots)
graphbb = _inspectdr_to_pixels(plotarea(sp))
plot = mplot.subplots[i]
plot.plotbb = InspectDR.plotbounds(plot.layout, graphbb)
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
end
gplot = _inspectdr_getgui(plt.o)
+27 -6
View File
@@ -435,6 +435,7 @@ function plotly_series(plt::Plot, series::Series)
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d)
hasfillrange = st in (:path, :scatter, :scattergl) && isa(series[:fillrange], AbstractVector)
# for surface types, set the data
if st in (:heatmap, :contour, :surface, :wireframe)
@@ -461,8 +462,11 @@ function plotly_series(plt::Plot, series::Series)
if series[:fillrange] == true || series[:fillrange] == 0
d_out[:fill] = "tozeroy"
d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif isa(series[:fillrange], AbstractVector)
d_out[:fill] = "tonexty"
d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif !(series[:fillrange] in (false, nothing))
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(series[:fillrange])")
warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
end
d_out[:x], d_out[:y] = x, y
@@ -479,6 +483,7 @@ function plotly_series(plt::Plot, series::Series)
d_out[:type] = "heatmap"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:showscale] = sp[:legend] != :none
elseif st == :contour
d_out[:type] = "contour"
@@ -487,6 +492,7 @@ function plotly_series(plt::Plot, series::Series)
d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
d_out[:showscale] = sp[:legend] != :none
elseif st in (:surface, :wireframe)
d_out[:type] = "surface"
@@ -499,11 +505,14 @@ function plotly_series(plt::Plot, series::Series)
:highlightwidth => series[:linewidth],
)
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
d_out[:showscale] = false
else
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:opacity] = series[:fillalpha]
if series[:fill_z] != nothing
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
end
d_out[:showscale] = sp[:legend] != :none
end
elseif st == :pie
@@ -546,7 +555,7 @@ function plotly_series(plt::Plot, series::Series)
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
grad = as_gradient(series[:markercolor], series[:markeralpha])
zmin, zmax = ignoreNaN_extrema(series[:marker_z])
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]]
end
@@ -572,7 +581,19 @@ function plotly_series(plt::Plot, series::Series)
plotly_polar!(d_out, series)
plotly_hover!(d_out, series[:hover])
[d_out]
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
# series, one for series being filled to) instead of one
d_out_fillrange = copy(d_out)
d_out_fillrange[:y] = series[:fillrange]
d_out_fillrange[:showlegend] = false
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
return [d_out_fillrange, d_out]
else
return [d_out]
end
end
function plotly_series_shapes(plt::Plot, series::Series)
@@ -600,18 +621,18 @@ function plotly_series_shapes(plt::Plot, series::Series)
:x => vcat(x[rng], x[rng[1]]),
:y => vcat(y[rng], y[rng[1]]),
:fill => "tozeroy",
:fillcolor => rgba_string(cycle(series[:fillcolor], i)),
:fillcolor => rgba_string(_cycle(series[:fillcolor], i)),
))
if series[:markerstrokewidth] > 0
d_out[:line] = KW(
:color => rgba_string(cycle(series[:linecolor], i)),
:color => rgba_string(_cycle(series[:linecolor], i)),
:width => series[:linewidth],
:dash => string(series[:linestyle]),
)
end
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotly_polar!(d_out, series)
plotly_hover!(d_out, cycle(series[:hover], i))
plotly_hover!(d_out, _cycle(series[:hover], i))
push!(d_outs, d_out)
end
d_outs
+56 -47
View File
@@ -70,18 +70,26 @@ function _initialize_backend(::PyPlotBackend)
append!(Base.Multimedia.displays, otherdisplays)
export PyPlot
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
const pypatches = PyPlot.pywrap(PyPlot.pyimport("matplotlib.patches"))
const pyfont = PyPlot.pywrap(PyPlot.pyimport("matplotlib.font_manager"))
const pyticker = PyPlot.pywrap(PyPlot.pyimport("matplotlib.ticker"))
const pycmap = PyPlot.pywrap(PyPlot.pyimport("matplotlib.cm"))
const pynp = PyPlot.pywrap(PyPlot.pyimport("numpy"))
pynp.seterr(invalid="ignore")
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"))
const pycolors = PyPlot.pyimport("matplotlib.colors")
const pypath = PyPlot.pyimport("matplotlib.path")
const mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
const pypatches = PyPlot.pyimport("matplotlib.patches")
const pyfont = PyPlot.pyimport("matplotlib.font_manager")
const pyticker = PyPlot.pyimport("matplotlib.ticker")
const pycmap = PyPlot.pyimport("matplotlib.cm")
const pynp = PyPlot.pyimport("numpy")
pynp["seterr"](invalid="ignore")
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
const pycollections = PyPlot.pyimport("matplotlib.collections")
const pyart3d = PyPlot.pyimport("mpl_toolkits.mplot3d.art3d")
# "support" matplotlib v1.5
const set_facecolor_sym = if PyPlot.version < v"2"
warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0")
:set_axis_bgcolor
else
:set_facecolor
end
# we don't want every command to update the figure
PyPlot.ioff()
@@ -101,7 +109,7 @@ end
# function py_colormap(c::ColorGradient, α=nothing)
# pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values]
# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
# pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
# end
# # convert vectors and ColorVectors to standard ColorGradients
@@ -118,7 +126,7 @@ py_color(grad::ColorGradient) = py_color(grad.colors)
function py_colormap(grad::ColorGradient)
pyvals = [(z, py_color(grad[z])) for z in grad.values]
cm = pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals)
cm = pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
cm[:set_bad](color=(0,0,0,0.0), alpha=0.0)
cm
end
@@ -127,7 +135,7 @@ py_colormap(c) = py_colormap(cgrad())
function py_shading(c, z)
cmap = py_colormap(c)
ls = pycolors.pymember("LightSource")(270,45)
ls = pycolors["LightSource"](270,45)
ls[:shade](z, cmap, vert_exag=0.1, blend_mode="soft")
end
@@ -151,7 +159,7 @@ function py_marker(marker::Shape)
mat[i,2] = y[i]
end
mat[n+1,:] = mat[1,:]
pypath.pymember("Path")(mat)
pypath["Path"](mat)
end
const _path_MOVETO = UInt8(1)
@@ -177,7 +185,7 @@ const _path_CLOSEPOLY = UInt8(79)
# lastnan = nan
# end
# codes[n+1] = _path_CLOSEPOLY
# pypath.pymember("Path")(mat, codes)
# pypath["Path"](mat, codes)
# end
# get the marker shape
@@ -227,14 +235,14 @@ end
# # untested... return a FontProperties object from a Plots.Font
# function py_font(font::Font)
# pyfont.pymember("FontProperties")(
# pyfont["FontProperties"](
# family = font.family,
# size = font.size
# )
# end
function get_locator_and_formatter(vals::AVec)
pyticker.pymember("FixedLocator")(1:length(vals)), pyticker.pymember("FixedFormatter")(vals)
pyticker["FixedLocator"](1:length(vals)), pyticker["FixedFormatter"](vals)
end
function add_pyfixedformatter(cbar, vals::AVec)
@@ -256,9 +264,9 @@ function labelfunc(scale::Symbol, backend::PyPlotBackend)
end
function py_mask_nans(z)
# PyPlot.pywrap(pynp.ma[:masked_invalid](PyPlot.pywrap(z)))
PyCall.pycall(pynp.ma[:masked_invalid], Any, z)
# pynp.ma[:masked_where](pynp.isnan(z),z)
# pynp["ma"][:masked_invalid](z)))
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
end
# ---------------------------------------------------------------------------
@@ -489,30 +497,30 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw = KW()
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
kw[:norm] = pycolors.Normalize(; extrakw...)
kw[:norm] = pycolors["Normalize"](; extrakw...)
end
lz = collect(series[:line_z])
handle = if is3d(st)
for rng in iter_segments(x, y, z)
length(rng) < 2 && continue
push!(segments, [(cycle(x,i),cycle(y,i),cycle(z,i)) for i in rng])
push!(segments, [(_cycle(x,i),_cycle(y,i),_cycle(z,i)) for i in rng])
end
# for i=1:n
# segments[i] = [(cycle(x,i), cycle(y,i), cycle(z,i)), (cycle(x,i+1), cycle(y,i+1), cycle(z,i+1))]
# segments[i] = [(_cycle(x,i), _cycle(y,i), _cycle(z,i)), (_cycle(x,i+1), _cycle(y,i+1), _cycle(z,i+1))]
# end
lc = pyart3d.Line3DCollection(segments; kw...)
lc = pyart3d["Line3DCollection"](segments; kw...)
lc[:set_array](lz)
ax[:add_collection3d](lc, zs=z) #, zdir='y')
lc
else
for rng in iter_segments(x, y)
length(rng) < 2 && continue
push!(segments, [(cycle(x,i),cycle(y,i)) for i in rng])
push!(segments, [(_cycle(x,i),_cycle(y,i)) for i in rng])
end
# for i=1:n
# segments[i] = [(cycle(x,i), cycle(y,i)), (cycle(x,i+1), cycle(y,i+1))]
# segments[i] = [(_cycle(x,i), _cycle(y,i)), (_cycle(x,i+1), _cycle(y,i+1))]
# end
lc = pycollections.LineCollection(segments; kw...)
lc = pycollections["LineCollection"](segments; kw...)
lc[:set_array](lz)
ax[:add_collection](lc)
lc
@@ -581,16 +589,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
lw = py_dpi_scale(plt, series[:markerstrokewidth])
for i=1:length(y)
extrakw[:c] = if series[:marker_z] == nothing
py_color_fix(py_color(cycle(series[:markercolor],i)), x)
py_color_fix(py_color(_cycle(series[:markercolor],i)), x)
else
extrakw[:c]
end
push!(handle, ax[:scatter](cycle(x,i), cycle(y,i);
push!(handle, ax[:scatter](_cycle(x,i), _cycle(y,i);
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
marker = py_marker(cycle(shapes,i)),
s = py_dpi_scale(plt, cycle(series[:markersize],i) .^ 2),
marker = py_marker(_cycle(shapes,i)),
s = py_dpi_scale(plt, _cycle(series[:markersize],i) .^ 2),
edgecolors = msc,
linewidths = lw,
extrakw...
@@ -705,11 +713,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" ? ignorenan_maximum : ignorenan_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" ? ignorenan_maximum : ignorenan_minimum)(mat) # where to draw the contour plane
)
push!(handles, handle)
needs_colorbar = true
@@ -768,7 +776,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
if st == :heatmap
x, y, z = heatmap_edges(x), heatmap_edges(y), transpose_z(series, z.surf)
x, y, z = heatmap_edges(x, sp[:xaxis][:scale]), heatmap_edges(y, sp[:yaxis][:scale]), transpose_z(series, z.surf)
expand_extrema!(sp[:xaxis], x)
expand_extrema!(sp[:yaxis], y)
@@ -778,7 +786,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
clims = sp[:clims]
zmin, zmax = ignoreNaN_extrema(z)
zmin, zmax = ignorenan_extrema(z)
extrakw[:vmin] = (is_2tuple(clims) && isfinite(clims[1])) ? clims[1] : zmin
extrakw[:vmax] = (is_2tuple(clims) && isfinite(clims[2])) ? clims[2] : zmax
@@ -797,13 +805,13 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
handle = []
for (i,rng) in enumerate(iter_segments(x, y))
if length(rng) > 1
path = pypath.pymember("Path")(hcat(x[rng], y[rng]))
patches = pypatches.pymember("PathPatch")(
path = pypath["Path"](hcat(x[rng], y[rng]))
patches = pypatches["PathPatch"](
path;
label = series[:label],
zorder = series[:series_plotindex],
edgecolor = py_color(cycle(series[:linecolor], i)),
facecolor = py_color(cycle(series[:fillcolor], i)),
edgecolor = py_color(_cycle(series[:linecolor], i)),
facecolor = py_color(_cycle(series[:fillcolor], i)),
linewidth = py_dpi_scale(plt, series[:linewidth]),
fill = true
)
@@ -926,7 +934,7 @@ 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 = NaNMath.min(minval, ignorenan_minimum(abs.(v)))
end
end
end
@@ -985,7 +993,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
fig[:clear]()
dpi = plt[:dpi]
fig[:set_size_inches](w/dpi, h/dpi, forward = true)
fig[:set_facecolor](py_color(plt[:background_color_outside]))
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
fig[:set_dpi](dpi)
# resize the window
@@ -1074,7 +1082,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_facecolor_sym](py_color(sp[:background_color_inside]))
end
py_drawfig(fig)
end
@@ -1166,7 +1174,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
# add a line/marker and a label
push!(handles, if series[:seriestype] == :shape
PyPlot.plt[:Line2D]((0,1),(0,0),
color = py_color(cycle(series[:fillcolor],1)),
color = py_color(_cycle(series[:fillcolor],1)),
linewidth = py_dpi_scale(plt, 4)
)
else
@@ -1196,7 +1204,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
# set some legend properties
frame = leg[:get_frame]()
frame[:set_facecolor](py_color(sp[:background_color_legend]))
frame[set_facecolor_sym](py_color(sp[:background_color_legend]))
frame[:set_edgecolor](fgcolor)
end
end
@@ -1220,7 +1228,8 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
if haskey(sp.attr, :cbar_ax)
cbw = sp.attr[:cbar_width]
# this is the bounding box of just the colors of the colorbar (not labels)
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox)+2mm, _cbar_width-1mm, height(sp.bbox)-4mm)
has_toplabel = sp[:zaxis][:extrema].emax >= 1e7
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox) + (has_toplabel ? 4mm : 2mm), _cbar_width-1mm, height(sp.bbox) - (has_toplabel ? 6mm : 4mm))
pcts = bbox_to_pcts(cb_bbox, figw, figh)
sp.attr[:cbar_ax][:set_position](pcts)
end
+28 -7
View File
@@ -297,12 +297,33 @@ function scalefontsize(k::Symbol, factor::Number)
f.pointsize = round(Int, factor * f.pointsize)
default(k, f)
end
"""
scalefontsizes(factor::Number)
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
"""
function scalefontsizes(factor::Number)
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
scalefontsize(k, factor)
end
end
"""
scalefontsizes()
Resets font sizes to initial default values.
"""
function scalefontsizes()
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
f = default(k)
if k in keys(_initial_fontsizes)
factor = f.pointsize / _initial_fontsizes[k]
scalefontsize(k, 1.0/factor)
end
end
end
"Wrap a string with font info"
immutable PlotText
str::AbstractString
@@ -446,7 +467,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
msw,msh = anns.scalefactor
msize = Float64[]
shapes = Shape[begin
str = cycle(anns.strs,i)
str = _cycle(anns.strs,i)
# get the width and height of the string (in mm)
sw, sh = text_size(str, anns.font.pointsize)
@@ -462,7 +483,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# and then re-scale a copy of baseshape to match the w/h ratio
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = cycle(get(anns.baseshape),i)
baseshape = _cycle(get(anns.baseshape),i)
shape = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end for i=1:length(anns.strs)]
series[:markershape] = shapes
@@ -479,13 +500,13 @@ end
Base.start(ea::EachAnn) = 1
Base.done(ea::EachAnn, i) = ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
function Base.next(ea::EachAnn, i)
tmp = cycle(ea.anns.strs,i)
tmp = _cycle(ea.anns.strs,i)
str,fnt = if isa(tmp, PlotText)
tmp.str, tmp.font
else
tmp, ea.anns.font
end
((cycle(ea.x,i), cycle(ea.y,i), str, fnt), i+1)
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
end
annotations(::Void) = []
@@ -501,13 +522,13 @@ 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} = (ignorenan_minimum(values), ignorenan_maximum(values)))
ZValues(collect(float(values)), map(Float64, zrange))
end
# -----------------------------------------------------------------------
abstract AbstractSurface
abstract type AbstractSurface end
"represents a contour or surface mesh"
immutable Surface{M<:AMat} <: AbstractSurface
@@ -659,7 +680,7 @@ function directed_curve(args...; kw...)
end
function extrema_plus_buffer(v, buffmult = 0.2)
vmin,vmax = ignoreNaN_extrema(v)
vmin,vmax = ignorenan_extrema(v)
vdiff = vmax-vmin
buffer = vdiff * buffmult
vmin - buffer, vmax + buffer
+1 -1
View File
@@ -84,7 +84,7 @@ function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray,
x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in cycle(geom.vertices, i)]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
end
Gadfly.polygon(polys, geom.tag)
end
+1 -1
View File
@@ -1,5 +1,5 @@
abstract ColorScheme
abstract type ColorScheme end
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
+10 -9
View File
@@ -41,7 +41,7 @@ PlotExample("Colors",
[:(begin
y = rand(100)
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=0, α=0.6)
scatter!(y, zcolor=abs(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs(y-0.5)+4, lab="grad")
scatter!(y, zcolor=abs.(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y-0.5)+4, lab="grad")
end)]
),
@@ -66,8 +66,8 @@ PlotExample("Global",
PlotExample("Images",
"Plot an image. y-axis is set to flipped",
[:(begin
import Images
img = Images.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
import FileIO
img = FileIO.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
plot(img)
end)]
),
@@ -119,17 +119,18 @@ PlotExample("Line styles",
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20,n),1)
plot(y, line = (5, styles), label = map(string,styles))
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
),
PlotExample("Marker types",
"",
[:(begin
markers = filter(m -> m in Plots.supported_markers(), Plots._shape_keys)'
markers = filter(m -> m in Plots.supported_markers(), Plots._shape_keys)
markers = reshape(markers, 1, length(markers))
n = length(markers)
x = linspace(0,10,n+2)[2:end-1]
y = repmat(reverse(x)', n, 1)
y = repmat(reshape(reverse(x),1,:), n, 1)
scatter(x, y, m=(8,:auto), lab=map(string,markers), bg=:linen, xlim=(0,10), ylim=(0,10))
end)]
),
@@ -215,7 +216,7 @@ PlotExample("Contours",
x = 1:0.5:20
y = 1:0.5:10
f(x,y) = (3x+y^2)*abs(sin(x)+cos(y))
X = repmat(x', length(y), 1)
X = repmat(reshape(x,1,:), length(y), 1)
Y = repmat(y, 1, length(x))
Z = map(f, X, Y)
p1 = contour(x, y, f, fill=true)
@@ -269,7 +270,7 @@ PlotExample("Polar Plots",
"",
[:(begin
Θ = linspace(0,1.5π,100)
r = abs(0.1randn(100)+sin(3Θ))
r = abs.(0.1randn(100)+sin.(3Θ))
plot(Θ, r, proj=:polar, m=2)
end)]
),
@@ -279,7 +280,7 @@ PlotExample("Heatmap, categorical axes, and aspect_ratio",
[:(begin
xs = [string("x",i) for i=1:10]
ys = [string("y",i) for i=1:4]
z = float((1:4)*(1:10)')
z = float((1:4)*reshape(1:10,1,:))
heatmap(xs, ys, z, aspect_ratio=1)
end)]
),
+3 -3
View File
@@ -9,8 +9,8 @@ to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm
Base.:.*(m::Measure, n::Number) = m * n
Base.:.*(n::Number, m::Measure) = m * n
Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
Base.zero(::Type{typeof(mm)}) = 0mm
@@ -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, ignorenan_extrema(a2))
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
a2[k] = a1[k]
end
+39 -44
View File
@@ -220,14 +220,10 @@ if is_installed("FileIO")
FileIO.save(pngfn, s)
# now write from the file
write(io, readall(open(pngfn)))
write(io, readstring(open(pngfn)))
end
end
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
@@ -250,76 +246,75 @@ end
const _ijulia_output = String["text/html"]
function setup_ijulia()
# override IJulia inline display
if isijulia()
@eval begin
import IJulia
export set_ijulia_output
function set_ijulia_output(mimestr::AbstractString)
# info("Setting IJulia output format to $mimestr")
global _ijulia_output
_ijulia_output[1] = mimestr
end
function IJulia.display_dict(plt::Plot)
global _ijulia_output
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
end
using Requires
@require IJulia begin
if IJulia.inited
export set_ijulia_output
# default text/plain passes to html... handles Interact issues
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
show(io, MIME("text/html"), plt)
end
function set_ijulia_output(mimestr::AbstractString)
# info("Setting IJulia output format to $mimestr")
global _ijulia_output
_ijulia_output[1] = mimestr
end
@eval set_ijulia_output("text/html")
function IJulia.display_dict(plt::Plot)
global _ijulia_output
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
end
# default text/plain passes to html... handles Interact issues
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
show(io, MIME("text/html"), plt)
end
set_ijulia_output("text/html")
end
end
# ---------------------------------------------------------
# Atom PlotPane
# ---------------------------------------------------------
@require Juno begin
import Hiccup, Media
function setup_atom()
if isatom()
@eval import Atom, Media
if Juno.isactive()
Media.media(Plot, Media.Plot)
# default text/plain so it doesn't complain
function Base.show{B}(io::IO, ::MIME"text/plain", plt::Plot{B})
print(io, "Plot{$B}()")
end
function Media.render(e::Atom.Editor, plt::Plot)
Media.render(e, nothing)
_show{B}(io::IO, m::MIME"text/plain", plt::Plot{B}) = print(io, "Plot{$B}()")
function Juno.render(e::Juno.Editor, plt::Plot)
Juno.render(e, nothing)
end
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
# this is like "display"... sends an html div with the plot to the PlotPane
function Media.render(pane::Atom.PlotPane, plt::Plot)
function Juno.render(pane::Juno.PlotPane, plt::Plot)
# temporarily overwrite size to be Atom.plotsize
sz = plt[:size]
plt[:size] = Juno.plotsize()
Media.render(pane, Atom.div(".fill", Atom.HTML(stringmime(MIME("text/html"), plt))))
jsize = Juno.plotsize()
jsize[1] == 0 && (jsize[1] = 400)
jsize[2] == 0 && (jsize[2] = 500)
plt[:size] = jsize
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
plt[:size] = sz
end
# special handling for PlotlyJS
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyJSBackend})
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
display(Plots.PlotsDisplay(), plt)
end
else
#
function Media.render(pane::Atom.PlotPane, plt::Plot)
function Juno.render(pane::Juno.PlotPane, plt::Plot)
display(Plots.PlotsDisplay(), plt)
s = "PlotPane turned off. Unset ENV[\"PLOTS_USE_ATOM_PLOTPANE\"] and restart Julia to enable it."
Media.render(pane, Atom.div(Atom.HTML(s)))
Juno.render(pane, HTML(s))
end
end
# special handling for plotly... use PlotsDisplay
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
function Juno.render(pane::Juno.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."
Media.render(pane, Atom.div(Atom.HTML(s)))
Juno.render(pane, HTML(s))
end
end
end
+2 -2
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 = [ignorenan_minimum(x), ignorenan_maximum(x)]
sy = β * sx + α
push!(kw_list, merge(copy(kw), KW(
:seriestype => :path,
@@ -262,7 +262,7 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
for kw in kw_list
# get the Subplot object to which the series belongs.
sps = get(kw, :subplot, :auto)
sp = get_subplot(plt, cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
kw[:subplot] = sp
# extract subplot/axis attributes from kw and add to sp_attr
+1 -1
View File
@@ -60,7 +60,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
# build our plot vector from the args
n = length(plts_tail) + 1
plts = Array(Plot, n)
plts = Array{Plot}(n)
plts[1] = plt1
for (i,plt) in enumerate(plts_tail)
plts[i+1] = plt
+38 -87
View File
@@ -1,53 +1,4 @@
"""
You can easily define your own plotting recipes with convenience methods:
```
@userplot type GroupHist
args
end
@recipe function f(gh::GroupHist)
# set some attributes, add some series, using gh.args as input
end
# now you can plot like:
grouphist(rand(1000,4))
```
"""
macro userplot(expr)
_userplot(expr)
end
function _userplot(expr::Expr)
if expr.head != :type
errror("Must call userplot on a type/immutable expression. Got: $expr")
end
typename = expr.args[2]
funcname = Symbol(lowercase(string(typename)))
funcname2 = Symbol(funcname, "!")
# return a code block with the type definition and convenience plotting methods
esc(quote
$expr
export $funcname, $funcname2
$funcname(args...; kw...) = plot($typename(args); kw...)
$funcname2(args...; kw...) = plot!($typename(args); kw...)
end)
end
function _userplot(sym::Symbol)
_userplot(:(type $sym
args
end))
end
# ----------------------------------------------------------------------------------
const _series_recipe_deps = Dict()
function series_recipe_dependencies(st::Symbol, deps::Symbol...)
@@ -96,7 +47,7 @@ end
num_series(x::AMat) = size(x,2)
num_series(x) = 1
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::Plot) = throw(MethodError("Unmatched plot recipe: $T"))
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::AbstractPlot) = throw(MethodError("Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
@@ -225,14 +176,14 @@ end
fr = if yaxis[:scale] == :identity
0.0
else
NaNMath.min(axis_limits(yaxis)[1], ignoreNaN_minimum(y))
NaNMath.min(axis_limits(yaxis)[1], ignorenan_minimum(y))
end
end
newx, newy = zeros(3n), zeros(3n)
for i=1:n
rng = 3i-2:3i
newx[rng] = [x[i], x[i], NaN]
newy[rng] = [cycle(fr,i), y[i], NaN]
newy[rng] = [_cycle(fr,i), y[i], NaN]
end
x := newx
y := newy
@@ -284,16 +235,16 @@ end
for rng in iter_segments(args...)
length(rng) < 2 && continue
ts = linspace(0, 1, npoints)
nanappend!(newx, map(t -> bezier_value(cycle(x,rng), t), ts))
nanappend!(newy, map(t -> bezier_value(cycle(y,rng), t), ts))
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts))
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts))
if z != nothing
nanappend!(newz, map(t -> bezier_value(cycle(z,rng), t), ts))
nanappend!(newz, map(t -> bezier_value(_cycle(z,rng), t), ts))
end
if fr != nothing
nanappend!(newfr, map(t -> bezier_value(cycle(fr,rng), t), ts))
nanappend!(newfr, map(t -> bezier_value(_cycle(fr,rng), t), ts))
end
# if lz != nothing
# lzrng = cycle(lz, rng) # the line_z's for this segment
# lzrng = _cycle(lz, rng) # the line_z's for this segment
# push!(newlz, 0.0)
# append!(newlz, map(t -> lzrng[1+floor(Int, t * (length(rng)-1))], ts))
# end
@@ -338,9 +289,9 @@ end
# compute half-width of bars
bw = d[:bar_width]
hw = if bw == nothing
0.5ignoreNaN_mean(diff(procx))
0.5ignorenan_mean(diff(procx))
else
Float64[0.5cycle(bw,i) for i=1:length(procx)]
Float64[0.5_cycle(bw,i) for i=1:length(procx)]
end
# make fillto a vector... default fills to 0
@@ -358,15 +309,15 @@ end
yi = procy[i]
if !isnan(yi)
center = procx[i]
hwi = cycle(hw,i)
fi = cycle(fillto,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
end
# widen limits out a bit
expand_extrema!(axis, widen(ignoreNaN_extrema(xseg.pts)...))
expand_extrema!(axis, widen(ignorenan_extrema(xseg.pts)...))
# switch back
if !isvertical(d)
@@ -414,8 +365,8 @@ 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)
w_min = ignorenan_minimum(w_adj)
w_max = ignorenan_maximum(w_adj)
baseline = _binbarlike_baseline(w_min, wscale)
w_adj, baseline
end
@@ -550,7 +501,7 @@ 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)))
_iqr(v) = quantile(v, 0.75) - quantile(v, 0.25)
_span(v) = ignoreNaN_maximum(v) - ignoreNaN_minimum(v)
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
n_samples = length(linearindices(first(vs)))
# Estimator for number of samples in one row/column of bins along each axis:
@@ -669,7 +620,7 @@ end
edge_x, edge_y, weights = x, y, z.surf
float_weights = float(weights)
if is(float_weights, weights)
if float_weights === weights
float_weights = deepcopy(float_weights)
end
for (i, c) in enumerate(float_weights)
@@ -752,12 +703,12 @@ end
function error_coords(xorig, yorig, ebar)
# init empty x/y, and zip errors if passed Tuple{Vector,Vector}
x, y = Array(float_extended_type(xorig), 0), Array(Float64, 0)
x, y = Array{float_extended_type(xorig)}(0), Array{Float64}(0)
# for each point, create a line segment from the bottom to the top of the errorbar
for i = 1:max(length(xorig), length(yorig))
xi = cycle(xorig, i)
yi = cycle(yorig, i)
ebi = cycle(ebar, i)
xi = _cycle(xorig, i)
yi = _cycle(yorig, i)
ebi = _cycle(ebar, i)
nanappend!(x, [xi, xi])
e1, e2 = if istuple(ebi)
first(ebi), last(ebi)
@@ -810,11 +761,11 @@ function quiver_using_arrows(d::KW)
x, y = zeros(0), zeros(0)
for i = 1:max(length(xorig), length(yorig))
# get the starting position
xi = cycle(xorig, i)
yi = cycle(yorig, i)
xi = _cycle(xorig, i)
yi = _cycle(yorig, i)
# get the velocity
vi = cycle(velocity, i)
vi = _cycle(velocity, i)
vx, vy = if istuple(vi)
first(vi), last(vi)
elseif isscalar(vi)
@@ -847,12 +798,12 @@ function quiver_using_hack(d::KW)
for i = 1:max(length(xorig), length(yorig))
# get the starting position
xi = cycle(xorig, i)
yi = cycle(yorig, i)
xi = _cycle(xorig, i)
yi = _cycle(yorig, i)
p = P2(xi, yi)
# get the velocity
vi = cycle(velocity, i)
vi = _cycle(velocity, i)
vx, vy = if istuple(vi)
first(vi), last(vi)
elseif isscalar(vi)
@@ -919,7 +870,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.3ignorenan_mean(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)
@@ -960,7 +911,7 @@ end
# "Sparsity plot... heatmap of non-zero values of a matrix"
# function spy{T<:Real}(z::AMat{T}; kw...)
# mat = map(zi->float(zi!=0), z)'
# mat = reshape(map(zi->float(zi!=0), z),1,:)
# xn, yn = size(mat)
# heatmap(mat; leg=false, yflip=true, aspect_ratio=:equal,
# xlim=(0.5, xn+0.5), ylim=(0.5, yn+0.5),
@@ -987,8 +938,8 @@ end
yflip := true
aspect_ratio := 1
rs, cs, zs = findnz(z.surf)
xlim := ignoreNaN_extrema(cs)
ylim := ignoreNaN_extrema(rs)
xlim := ignorenan_extrema(cs)
ylim := ignorenan_extrema(rs)
if d[:markershape] == :none
markershape := :circle
end
@@ -1010,7 +961,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, [ignorenan_extrema(plt)...], x -> b + a*x; kw...)
end
abline!(args...; kw...) = abline!(current(), args...; kw...)
@@ -1019,11 +970,11 @@ abline!(args...; kw...) = abline!(current(), args...; kw...)
# -------------------------------------------------
# Dates
dateformatter(dt) = string(convert(Date, dt))
datetimeformatter(dt) = string(convert(DateTime, dt))
dateformatter(dt) = string(Date(Dates.UTD(dt)))
datetimeformatter(dt) = string(DateTime(Dates.UTM(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 -> Dates.value(dt), dateformatter)
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
# -------------------------------------------------
# Complex Numbers
@@ -1054,7 +1005,7 @@ end
end
library = PlotUtils.color_libraries[cl.args[1]]
z = sqrt.((1:15)*(1:20)')
z = sqrt.((1:15)*reshape(1:20,1,:))
seriestype := :heatmap
ticks := nothing
@@ -1078,7 +1029,7 @@ end
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)')
z = sqrt.((1:15)*reshape(1:20,1,:))
seriestype := :heatmap
ticks := nothing
legend := false
+2 -2
View File
@@ -6,7 +6,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
typealias FuncOrFuncs{F} Union{F, Vector{F}, Matrix{F}}
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
@@ -318,7 +318,7 @@ end
@recipe function f{T<:Colorant}(mat::AMat{T})
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
SliceIt, 1:m, 1:n, Surface(mat)
+1 -1
View File
@@ -32,7 +32,7 @@ get_subplot(plt::Plot, k) = plt.spmap[k]
get_subplot(series::Series) = series.d[:subplot]
get_subplot_index(plt::Plot, idx::Integer) = Int(idx)
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots)
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(x -> x === sp, plt.subplots)
series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
-4
View File
@@ -8,10 +8,6 @@ const KW = Dict{Symbol,Any}
immutable PlotsDisplay <: Display end
abstract AbstractBackend
abstract AbstractPlot{T<:AbstractBackend}
abstract AbstractLayout
# -----------------------------------------------------------
immutable InputWrapper{T}
+44 -31
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 = ignorenan_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 = [ignorenan_minimum(x), ignorenan_maximum(x)]
regy = β * regx + α
regx, regy
end
@@ -192,7 +192,7 @@ function iter_segments(args...)
end
# helpers to figure out if there are NaN values in a list of array types
anynan(i::Int, args::Tuple) = any(a -> !isfinite(cycle(a,i)), args)
anynan(i::Int, args::Tuple) = any(a -> !isfinite(_cycle(a,i)), args)
anynan(istart::Int, iend::Int, args::Tuple) = any(i -> anynan(i, args), istart:iend)
allnan(istart::Int, iend::Int, args::Tuple) = all(i -> anynan(i, args), istart:iend)
@@ -243,19 +243,19 @@ notimpl() = error("This has not been implemented yet")
isnothing(x::Void) = true
isnothing(x) = false
cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
_cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
_cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
cycle(v, idx::Int) = v
_cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
_cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
_cycle(v, idx::Int) = v
cycle(v::AVec, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
cycle(v::AMat, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
cycle(v, indices::AVec{Int}) = fill(v, length(indices))
_cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
_cycle(v::AMat, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
_cycle(v, indices::AVec{Int}) = fill(v, length(indices))
cycle(grad::ColorGradient, idx::Int) = cycle(grad.colors, idx)
cycle(grad::ColorGradient, indices::AVec{Int}) = cycle(grad.colors, indices)
_cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
makevec(v::AVec) = v
makevec{T}(v::T) = T[v]
@@ -283,7 +283,7 @@ 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)
e1, e2 = ignorenan_extrema(x)
lims[1] = NaNMath.min(lims[1], e1)
lims[2] = NaNMath.max(lims[2], e2)
# catch err
@@ -292,7 +292,7 @@ function _expand_limits(lims, x)
nothing
end
expand_data(v, n::Integer) = [cycle(v, i) for i=1:n]
expand_data(v, n::Integer) = [_cycle(v, i) for i=1:n]
# if the type exists in a list, replace the first occurence. otherwise add it to the end
function addOrReplace(v::AbstractVector, t::DataType, args...; kw...)
@@ -324,7 +324,7 @@ function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
end
end
createSegments(z) = collect(repmat(z',2,1))[2:end]
createSegments(z) = collect(repmat(reshape(z,1,:),2,1))[2:end]
Base.first(c::Colorant) = c
Base.first(x::Symbol) = x
@@ -332,19 +332,32 @@ Base.first(x::Symbol) = x
sortedkeys(d::Dict) = sort(collect(keys(d)))
const _scale_base = Dict{Symbol, Real}(
:log10 => 10,
:log2 => 2,
:ln => e,
)
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec)
vmin, vmax = ignoreNaN_extrema(v)
extra = 0.5 * (vmax-vmin) / (length(v)-1)
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
function heatmap_edges(v::AVec, scale::Symbol = :identity)
vmin, vmax = ignorenan_extrema(v)
extra_min = extra_max = 0.5 * (vmax-vmin) / (length(v)-1)
if scale in _logScales
vmin > 0 || error("The axis values must be positive for a $scale scale")
while vmin - extra_min <= 0
extra_min /= _scale_base[scale]
end
end
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
end
function calc_r_extrema(x, y)
xmin, xmax = ignoreNaN_extrema(x)
ymin, ymax = ignoreNaN_extrema(y)
xmin, xmax = ignorenan_extrema(x)
ymin, ymax = ignorenan_extrema(y)
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
ignoreNaN_extrema(r)
ignorenan_extrema(r)
end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
@@ -355,8 +368,8 @@ function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
x = zeros(n)
y = zeros(n)
for i in 1:n
x[i] = cycle(r,i) * cos(cycle(phi,i))
y[i] = cycle(r,i) * sin(cycle(phi,i))
x[i] = _cycle(r,i) * cos.(_cycle(phi,i))
y[i] = _cycle(r,i) * sin.(_cycle(phi,i))
end
x, y
end
@@ -469,7 +482,7 @@ ok(tup::Tuple) = ok(tup...)
# compute one side of a fill range from a ribbon
function make_fillrange_side(y, rib)
frs = zeros(length(y))
for (i, (yi, ri)) in enumerate(zip(y, Base.cycle(rib)))
for (i, (yi, ri)) in enumerate(zip(y, Base.Iterators.cycle(rib)))
frs[i] = yi + ri
end
frs
@@ -480,7 +493,7 @@ function make_fillrange_from_ribbon(kw::KW)
y, rib = kw[:y], kw[:ribbon]
rib = wraptuple(rib)
rib1, rib2 = -first(rib), last(rib)
kw[:ribbon] = nothing
# kw[:ribbon] = nothing
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
end
@@ -645,7 +658,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) + ignorenan_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 +884,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) = ignorenan_minimum([ignorenan_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) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series in plt.series_list])
"Extrema of x-values in plot"
ignoreNaN_extrema(plt::Plot) = (xmin(plt), xmax(plt))
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
-2
View File
@@ -1,5 +1,4 @@
StatPlots
FactCheck
Images
ImageMagick
@osx QuartzImageIO
@@ -7,4 +6,3 @@ GR
RDatasets
VisualRegressionTests
UnicodePlots
Glob
+5 -10
View File
@@ -13,10 +13,9 @@ try
end
# using Plots # reexported by StatPlots
using Plots
using StatPlots
using FactCheck
using Glob
using Base.Test
default(size=(500,300))
@@ -24,7 +23,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# 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.12.1"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
@@ -43,11 +42,7 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
fn = "ref$idx.png"
# firgure out version info
G = glob(joinpath(relpath(refdir), "*"))
# @show refdir fn G
slash = (@static is_windows() ? "\\" : "/")
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
versions = reverse(sort(versions))
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
versions = filter(v -> v <= _current_plots_version, versions)
# @show refdir fn versions
@@ -99,7 +94,7 @@ function image_comparison_facts(pkg::Symbol;
for i in 1:length(Plots._examples)
i in skip && continue
if only == nothing || i in only
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
end
end
end
+2 -2
View File
@@ -6,8 +6,8 @@ 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 https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2.1_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
wkhtmltoimage http://www.google.com test.png
+48 -51
View File
@@ -7,41 +7,35 @@ srand(1234)
default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2
# facts("Gadfly") do
# @fact gadfly() --> Plots.GadflyBackend()
# @fact backend() --> Plots.GadflyBackend()
#
# @fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
# @fact plot(Int[1,2,3], rand(3)) --> not(nothing)
# @fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
# @fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
#
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# end
facts("GR") do
@fact gr() --> Plots.GRBackend()
@fact backend() --> Plots.GRBackend()
@testset "GR" begin
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
image_comparison_facts(:gr, eps=img_eps)
end
facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
@testset "PyPlot" begin
@test pyplot() == Plots.PyPlotBackend()
@test backend() == Plots.PyPlotBackend()
image_comparison_facts(:pyplot, eps=img_eps)
end
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
# lets just make sure it runs without error
@test isa(plot(rand(10)), Plots.Plot) == true
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()
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# if is_linux() && isinteractive()
# image_comparison_facts(:plotlyjs,
@@ -59,9 +53,9 @@ end
# 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()
# @testset "InspectDR" begin
# @test inspectdr() == Plots.InspectDRBackend()
# @test backend() == Plots.InspectDRBackend()
#
# image_comparison_facts(:inspectdr,
# skip=[
@@ -78,61 +72,66 @@ end
# end
# facts("Plotly") do
# @fact plotly() --> Plots.PlotlyBackend()
# @fact backend() --> Plots.PlotlyBackend()
# @testset "Plotly" begin
# @test plotly() == Plots.PlotlyBackend()
# @test 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()
# @testset "Immerse" begin
# @test immerse() == Plots.ImmerseBackend()
# @test backend() == Plots.ImmerseBackend()
#
# # as long as we can plot anything without error, it should be the same as Gadfly
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
# end
# facts("PlotlyJS") do
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
# @fact backend() --> Plots.PlotlyJSBackend()
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# # as long as we can plot anything without error, it should be the same as Plotly
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
# end
facts("UnicodePlots") do
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
@fact backend() --> Plots.UnicodePlotsBackend()
# lets just make sure it runs without error
@fact isa(plot(rand(10)), Plots.Plot) --> true
end
# @testset "Gadfly" begin
# @test gadfly() == Plots.GadflyBackend()
# @test backend() == Plots.GadflyBackend()
#
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
#
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# end
facts("Axes") do
@testset "Axes" begin
p = plot()
axis = p.subplots[1][:xaxis]
@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 axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
@test typeof(axis) == Plots.Axis
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
@test Plots.ignorenan_extrema(axis) == (0.5,1.5)
@test 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)
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
end
# tests for preprocessing recipes
# facts("recipes") do
# @testset "recipes" begin
# user recipe
@@ -169,6 +168,4 @@ end
# end
FactCheck.exitstatus()
end # module
+1 -1
View File
@@ -1,4 +1,4 @@
Pkg.clone("ImageMagick")
Pkg.add("ImageMagick")
Pkg.build("ImageMagick")
Pkg.clone("GR")