Compare commits

..

126 Commits

Author SHA1 Message Date
Josef Heinen b9c9fc615b Update gr.jl 2018-08-01 13:06:55 +02:00
Daniel Schwabeneder 50c62ec48e Merge pull request #1593 from fredrikekre/fe/0.72
small additional fixes for 0.7
2018-07-05 08:14:48 +02:00
Fredrik Ekre b16ced0367 small fixes 2018-07-05 00:19:21 +02:00
Daniel Schwabeneder 0717805773 more deprecation fixes 2018-07-04 22:33:51 +02:00
Daniel Schwabeneder a7f2484d45 fix some deprecation warnings 2018-07-04 20:56:13 +02:00
Daniel Schwabeneder 96d97699a0 Merge pull request #1588 from daschw/julia0.7
fix Pkg.installed
2018-07-03 20:02:22 +02:00
Daniel Schwabeneder e92e832258 fix Pkg.installed 2018-07-03 19:59:03 +02:00
femtocleaner[bot] d68829820b Fix deprecations 2018-06-30 23:15:27 +00:00
Daniel Schwabeneder 9cf3036ab5 Merge pull request #1587 from daschw/julia0.7
remove StatPlots from tests
2018-07-02 00:28:22 +02:00
Daniel Schwabeneder 2467eb71c1 remove StatPlots from tests 2018-07-02 00:26:23 +02:00
Daniel Schwabeneder 345bb5d1aa Merge pull request #1586 from daschw/julia0.7
use Pkg in travis commands
2018-07-02 00:19:54 +02:00
Daniel Schwabeneder 8d50828998 Merge branch 'julia0.7' into julia0.7 2018-07-02 00:03:27 +02:00
Daniel Schwabeneder 201de82baf fix some things in tests 2018-07-02 00:00:40 +02:00
Daniel Schwabeneder 99519ac3da use Pkg in travis commands 2018-07-01 23:48:56 +02:00
Daniel Schwabeneder a575ab7c74 Merge branch 'master' into julia0.7 2018-07-01 23:30:40 +02:00
Daniel Schwabeneder c4f79814df Merge pull request #1584 from daschw/julia0.7
julia 0.7 fixes
2018-07-01 23:24:38 +02:00
Daniel Schwabeneder 6135f6271c julia 0.7 fixes 2018-07-01 21:40:48 +02:00
Daniel Schwabeneder 0eab0dc680 Merge pull request #1583 from daschw/release
prepare release
2018-07-01 10:11:07 +02:00
Daniel Schwabeneder 2b48f50de4 prepare release 2018-07-01 10:06:49 +02:00
Daniel Schwabeneder fa60eacfc5 Merge pull request #1572 from daschw/widen
Widen axes for most series types and log scales
2018-07-01 09:52:29 +02:00
Daniel Schwabeneder d2a4136d4f Merge pull request #1582 from daschw/test
don't checkout PlotUtils in tests
2018-07-01 09:33:19 +02:00
Daniel Schwabeneder 7d88a746ea don't checkout PlotUtils in tests 2018-07-01 09:27:11 +02:00
Daniel Schwabeneder 7f4537bdc6 Merge pull request #1577 from JuliaPlots/pv/webio
WebIO integration for PlotlyJS backend
2018-07-01 08:44:40 +02:00
Andrew Palugniok 8ef70f07f0 Merge pull request #1576 from apalugniok/hover-zcolor
Fix hover and zcolor interaction in Plotly (Fixes #1567)
2018-06-28 08:28:42 +01:00
Andrew Palugniok 17b7e37885 Merge pull request #1575 from apalugniok/flip-plotly
Fix axis flip on Plotly (Fixes #1556)
2018-06-28 08:28:01 +01:00
Pietro Vertechi 35c17044e1 prepare output 2018-06-27 15:39:54 +01:00
Pietro Vertechi 7085d98f41 webio integration 2018-06-27 15:24:50 +01:00
Andrew Palugniok ee73e32b0e Fix hover and zcolor interaction in Plotly. 2018-06-26 18:26:13 +01:00
Andrew Palugniok 371430c172 Fix axis flip on Plotly. 2018-06-26 12:18:22 +01:00
Daniel Schwabeneder 495753b517 Merge pull request #1573 from yha/plotly-log-noticks
Plotly: fix log scale with no ticks
2018-06-25 15:59:12 +02:00
yharel 211be0a863 Setting axis scale regardless of ticks 2018-06-25 00:42:36 +03:00
Daniel Schwabeneder 12c9a8e6c3 plots_heatmap 2018-06-24 19:01:06 +02:00
Daniel Schwabeneder fb5d9e0c01 Merge pull request #1571 from daschw/pgf_dpi
New attributes for PGFPlots
2018-06-24 18:05:14 +02:00
Daniel Schwabeneder 61a2d962c0 widen most seriestypes including logscales 2018-06-24 11:03:56 +02:00
Daniel Schwabeneder 440622830a disregard dpi for pgfplots 2018-06-24 00:34:11 +02:00
Daniel Schwabeneder 2652990432 annotations 2018-06-23 23:44:43 +02:00
Daniel Schwabeneder 652e2f27b6 implement font rotation 2018-06-23 23:38:38 +02:00
Daniel Schwabeneder 77a82eaa6a implent font size and colors 2018-06-23 23:24:09 +02:00
Daniel Schwabeneder 624a181b23 implement axis and grid arguments and corresponding thickness_scaling 2018-06-23 21:47:01 +02:00
Daniel Schwabeneder 865ac52442 pgf_thickness_scaling for series linewidths and markers 2018-06-23 19:39:25 +02:00
Daniel Schwabeneder 4f064d7c02 Merge pull request #1561 from daschw/size
Fix size and dpi for GR and PyPlot
2018-06-23 09:14:52 +02:00
Daniel Schwabeneder facb67e94e Merge pull request #1570 from daschw/flip
fix flip for heatmap and image on GR (fix #1491)
2018-06-23 07:34:24 +02:00
Daniel Schwabeneder 124c838e06 fix flip for heatmap and image on GR 2018-06-22 22:07:00 +02:00
Daniel Schwabeneder 026e894e1d Merge pull request #1565 from daschw/fillrange
Fix fillrange with line segments on PyPlot and Plotly (fix #1563)
2018-06-18 21:58:36 +02:00
Daniel Schwabeneder 2ed0f1661a fix plotly fillrange 2018-06-18 19:55:09 +02:00
Daniel Schwabeneder 00f285cba3 fix pyplot fillrange 2018-06-18 19:45:43 +02:00
Daniel Schwabeneder ddf5bf472f Merge pull request #1562 from daschw/py_marker
fix markercolor as vector on pyplot (fix #1494)
2018-06-18 09:22:13 +02:00
Daniel Schwabeneder 534c7799e5 fix markercolor as vector on pyplot 2018-06-17 22:20:20 +02:00
Daniel Schwabeneder b254aaa081 Merge pull request #1559 from yha/log-heatmap
Log-scale heatmap edge computation
2018-06-16 21:24:23 +02:00
Daniel Schwabeneder 76f2860c74 fix gr 2018-06-16 20:38:46 +02:00
Daniel Schwabeneder 5ebcb77d0d rename _gr_dpi_scale to _gr_thickness_scaling 2018-06-16 19:29:28 +02:00
Daniel Schwabeneder 4847752ef4 make dpi change plot size 2018-06-16 19:24:58 +02:00
Daniel Schwabeneder 84ec8d61ae fix thickness_scaling in pyplot 2018-06-16 17:14:19 +02:00
Daniel Schwabeneder 0f13551b6d fix margins on gr 2018-06-16 16:57:07 +02:00
Daniel Schwabeneder 3e66c6cce4 change DPI value back 2018-06-16 11:51:49 +02:00
yha 09de3a5e7a GR heatmap: warning for non-equal spacing 2018-06-16 04:14:27 +03:00
yha 00483d4c0d GR heatmap: warning for non-equal spacing 2018-06-16 04:07:21 +03:00
yha 1e3d10ad31 GR heatmap: warning for non-equal spacing 2018-06-16 03:13:13 +03:00
yha dc31cd7103 A better heuristic for outer heatmap edges 2018-06-16 03:10:48 +03:00
yharel cffb670f72 Merge branch 'master' of https://github.com/JuliaPlots/Plots.jl 2018-06-14 04:06:08 +03:00
yharel 781fea7431 Heatmap log scale fix 2018-06-14 02:59:04 +03:00
Daniel Schwabeneder 78b0b7e01d Merge pull request #1557 from daschw/release
prepare release
2018-06-12 21:09:12 +02:00
Daniel Schwabeneder e96367cd4b prepare release 2018-06-12 21:07:45 +02:00
Daniel Schwabeneder 30af3c7f8a Merge pull request #1547 from wfrgra/round_axis_limits
allow automatic widening of the axis limits to the next power of 10 …
2018-06-06 21:48:52 +02:00
Daniel Schwabeneder 264405827e Merge pull request #1549 from daschw/plotly-lims
fix single subplot in plotly (fix #1485)
2018-06-06 21:48:31 +02:00
Daniel Schwabeneder 083721bbc1 fix single subplot in plotly 2018-06-06 18:25:22 +02:00
Will Grant 91ed04ff83 update documentation in arg_desc with round limits option 2018-06-06 18:44:07 +10:00
Will Grant cbbd4fd029 allow automatic widening of the axis limits to the next power of 10 with xlim/ylim = :round 2018-06-06 11:20:05 +10:00
Daniel Schwabeneder f6bc7721a8 Merge pull request #1536 from fredrikekre/fe/_show
restructure some show methods
2018-06-05 13:15:26 +02:00
Fredrik Ekre 32ec9e82bf make UnicodePlots print to the given io
and add support for text/plain in Plots own display_dict
fix #1514
2018-06-04 12:36:50 +02:00
Fredrik Ekre 69a7a8a04e define show for more mime-types 2018-06-04 12:36:50 +02:00
Fredrik Ekre ccb5194bb5 make fallback method a method of _show instead of show
fix #1529
2018-06-04 12:36:45 +02:00
Fredrik Ekre 2d280edf0c forward showable call to _show instead of show since all backends return true otherwise 2018-06-04 10:15:13 +02:00
Daniel Schwabeneder afe4817150 Merge pull request #1537 from fredrikekre/fe/fileio
only try the pdf -> png convert sometimes
2018-06-03 17:03:15 +02:00
Daniel Schwabeneder 6754b3746e Merge pull request #1543 from daschw/ticks
set fallback tick specification for axes with discrete values
2018-06-03 16:21:54 +02:00
Daniel Schwabeneder 287f83f4d0 Merge pull request #1544 from daschw/pyplot-legend
PyPlot: fix bg_legend = invisible()
2018-06-03 16:21:32 +02:00
Daniel Schwabeneder bf518a961e clean up 2018-05-30 16:28:56 +02:00
Daniel Schwabeneder 4a55467eef add plot_color 2018-05-30 16:20:19 +02:00
Daniel Schwabeneder 56cf5249f9 remove extra line 2018-05-30 16:18:56 +02:00
Daniel Schwabeneder 17e8bc6949 set legend alpha in pyplot 2018-05-30 16:13:39 +02:00
Daniel Schwabeneder 02ede8020f fix tick conditions 2018-05-30 14:26:35 +02:00
Daniel Schwabeneder 54158a0340 check for dvals at the end 2018-05-30 13:59:16 +02:00
Daniel Schwabeneder 7ce96a4e3d set fallback tick specification for axes with discrete values 2018-05-30 13:25:00 +02:00
Daniel Schwabeneder 2067b70445 Merge pull request #1535 from fredrikekre/fe/text/plain
add text/plain default, fix #1515
2018-05-22 14:29:16 +02:00
Fredrik Ekre d02658e0ba add text/plain default, fix #1515 2018-05-21 15:09:50 +02:00
Fredrik Ekre 27e68ed6a9 only try the pdf -> png convert if the backend support application/pdf mime 2018-05-21 14:49:18 +02:00
Daniel Schwabeneder b3e0ac017f Merge pull request #1534 from daschw/release
prepare release
2018-05-21 09:55:56 +02:00
Daniel Schwabeneder 8bc437a84e prepare release 2018-05-21 09:53:58 +02:00
Daniel Schwabeneder 11e5a94fc4 Merge pull request #1528 from jdeldre/je/fixcontour
Contour plots with x,y in grid (i.e. multi-dimensional array) form
2018-05-18 16:06:08 +02:00
Daniel Schwabeneder c11941cbc1 Merge pull request #1523 from daschw/seriesrecipe
update series attributes after processing series recipes fix (#1520)
2018-05-18 16:00:35 +02:00
Jeff Eldredge f792aea98e Changed treatment of contour types, to allow for x,y in grid form, allowed by PyPlot backend 2018-05-16 11:19:10 -07:00
Daniel Schwabeneder 12e5937a91 Merge pull request #1525 from daschw/plotly-ribbon
Fix Plotly(JS) ribbon (fix #1518)
2018-05-13 23:37:43 +02:00
Daniel Schwabeneder 60b9cd8789 remove space 2018-05-13 19:52:26 +02:00
Daniel Schwabeneder 41e4c80494 fix ribbon for plotly 2018-05-13 19:49:02 +02:00
Daniel Schwabeneder bd2756c0bf fix ribbon for plotly 2018-05-13 19:48:49 +02:00
Daniel Schwabeneder 1f3c4948c6 update series attributes after processing series recipes 2018-05-11 18:38:04 +02:00
Daniel Schwabeneder 062f9a195c Merge pull request #1522 from daschw/recipe-colors
make get_*color functions return plot_color (markercolor in series recipes in GR)
2018-05-11 14:25:02 +02:00
Daniel Schwabeneder a3e8af40b2 make get_***color return plot_color 2018-05-10 22:21:50 +02:00
Daniel Schwabeneder 49f4773e81 Merge pull request #1510 from chfin/segments-legendgroup-fix
Make series of shapes and segments toggle together in plotly[js] (fixes #1488)
2018-05-06 21:46:10 +02:00
Daniel Schwabeneder ee78385b4c Merge branch 'master' into segments-legendgroup-fix 2018-05-06 09:37:08 +02:00
Daniel Schwabeneder e99ccd0051 Merge pull request #1501 from daschw/integers
replace Int64 by Int
2018-05-06 09:31:52 +02:00
Daniel Schwabeneder cbc022524b Merge pull request #1511 from daschw/markercolors
fix marker arguments (fix #1503 fix #1505)
2018-05-06 09:30:25 +02:00
Daniel Schwabeneder 34d9d042aa update iter_segments for scatters 2018-05-05 21:42:08 +02:00
Daniel Schwabeneder 22f69a99e2 remove cfuncind in gr_draw_markers 2018-05-05 20:42:47 +02:00
Daniel Schwabeneder 4ee5539e3d plotly fixes 2018-05-05 19:22:34 +02:00
Daniel Schwabeneder 048636e894 fix plotly marker_z colorbar 2018-05-05 18:50:57 +02:00
Daniel Schwabeneder 5797ad2d5b fix plotly 2018-05-05 18:37:16 +02:00
Daniel Schwabeneder ba9a8d52cc pgfplots markercolors 2018-05-05 17:44:13 +02:00
Daniel Schwabeneder ee18a9dd6c plotly markercolors 2018-05-05 16:47:32 +02:00
Daniel Schwabeneder 517c2f456c markercolors for pyplot 2018-05-05 16:22:41 +02:00
Christoph Finkensiep e8734daa4d add legendgroups to shapes/segments and remove gaps in legend 2018-05-05 12:27:16 +02:00
Daniel Schwabeneder 1fd7c6e2f1 fix args.jl 2018-05-05 01:10:07 +02:00
Daniel Schwabeneder bc638ea06e first gr tests 2018-05-05 00:57:29 +02:00
Michael K. Borregaard 5b0ba79a35 Update Travis commands for 0.7 2018-05-04 10:53:21 +02:00
Michael Krabbe Borregaard 173c7b2aec Update julia version to 0.7
Isn't working yet.
2018-05-03 20:46:32 +02:00
Daniel Schwabeneder fd37a9c660 replace Int64 by Int 2018-04-27 17:44:20 +02:00
Daniel Schwabeneder fc460554e7 Merge pull request #1497 from daschw/markerstroke
fix markerstrokecolor = :auto (fix #1496)
2018-04-25 17:56:20 +02:00
Daniel Schwabeneder 73490903a3 fix markerstrokecolor = :auto 2018-04-25 14:14:20 +02:00
Daniel Schwabeneder 964c0ac420 Merge pull request #1489 from daschw/pgf-contour
fix contours in PGFPlots (fix #1321)
2018-04-18 17:28:26 +02:00
Daniel Schwabeneder f59ad1620a contour improvements: colorbar, contour_labels and levels 2018-04-18 16:13:28 +02:00
Daniel Schwabeneder 4797f18819 fix view for contours 2018-04-18 15:44:37 +02:00
Andrew Palugniok b0d73a3314 Merge pull request #1442 from apalugniok/native-ticks
Fixes for :native axes. (Fixes #1435 and partly #1425)
2018-04-17 12:38:23 +01:00
Michael Krabbe Borregaard 562e60f964 Merge pull request #1480 from ma-laforge/hdf5
Add support for Surface plots.
2018-04-15 12:50:36 +02:00
Andrew Palugniok aeaa0c5f8d Fix axis limits for ticks = :native 2018-04-09 21:28:45 +01:00
Andrew Palugniok b009da4b47 Fix :native DateTime and categorical ticks for Plotly. 2018-04-09 21:20:41 +01:00
MA Laforge bde415edd7 Add support for Surface plots. 2018-02-06 06:26:07 -05:00
40 changed files with 697 additions and 545 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ os:
- linux
# - osx
julia:
- 0.6
- 0.7
matrix:
allow_failures:
- julia: nightly
@@ -44,7 +44,7 @@ notifications:
# uncomment the following lines to override the default test script
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
- julia -e 'using Pkg; Pkg.add(pwd()); Pkg.build("Plots")'
- julia test/travis_commands.jl
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
+30 -1
View File
@@ -3,13 +3,42 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.15!
- Minor version 0.17 is the last one to support Julia 0.6!!
- Minor version 0.11 is the last one to support Julia 0.5!!
- Critical bugfixes only
- `backports` branch is for Julia 0.5
---
## (current master)
- All new development should target Julia 0.7!
## 0.17.3
- Log-scale heatmap edge computation
- Fix size and dpi for GR and PyPlot
- Fix fillrange with line segments on PyPlot and Plotly
- fix flip for heatmap and image on GR
- New attributes for PGFPlots
- Widen axes for most series types and log scales
- Plotly: fix log scale with no ticks
- Fix axis flip on Plotly
- Fix hover and zcolor interaction in Plotly
- WebIO integration for PlotlyJS backend
## 0.17.2
- fix single subplot in plotly
- implement `(xyz)lims = :round`
- PyPlot: fix bg_legend = invisible()
- set fallback tick specification for axes with discrete values
- restructure of show methods
## 0.17.1
- Fix contour for PGFPlots
- 32Bit fix: Int64 -> Int
- Make series of shapes and segments toggle together in Plotly(JS)
- Fix marker arguments
- Fix processing order of series recipes
- Fix Plotly(JS) ribbon
- Contour plots with x,y in grid form on PyPlot
## 0.17.0
- Add GR dependency to make it the default backend
+1 -1
View File
@@ -1,4 +1,4 @@
julia 0.6
julia 0.7-alpha
RecipesBase 0.2.3
PlotUtils 0.4.1
+1 -1
View File
@@ -3,6 +3,6 @@
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
end
+22 -21
View File
@@ -6,6 +6,7 @@ using Reexport
import StaticArrays
using StaticArrays.FixedSizeArrays
using Dates, Printf, Statistics, Base64, LinearAlgebra
@reexport using RecipesBase
import RecipesBase: plot, plot!, animate
@@ -264,29 +265,29 @@ xgrid!(args...; kw...) = plot!(; xgrid = args
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
let PlotOrSubplot = Union{Plot, Subplot}
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
xticks!(plt::PlotOrSubplot,
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
global xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
global xticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
yticks!(plt::PlotOrSubplot,
global yticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
end
+4 -2
View File
@@ -65,6 +65,7 @@ const _arg_desc = KW(
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
@@ -110,7 +111,7 @@ const _arg_desc = KW(
# axis args
:guide => "String. Axis guide (label).",
:lims => "NTuple{2,Number}. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
@@ -139,5 +140,6 @@ const _arg_desc = KW(
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`"
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
)
+40 -26
View File
@@ -15,7 +15,7 @@ function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
for (k,v) in aliases
s = string(k)
if '_' in s
aliases[Symbol(replace(s, "_", ""))] = v
aliases[Symbol(replace(s, "_" => ""))] = v
end
end
end
@@ -176,7 +176,7 @@ const _positionAliases = Dict{Symbol,Symbol}(
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
const _logScales = [:ln, :log2, :log10]
const _logScaleBases = Dict(:ln => e, :log2 => 2.0, :log10 => 10.0)
const _logScaleBases = Dict(:ln => , :log2 => 2.0, :log10 => 10.0)
const _scaleAliases = Dict{Symbol,Symbol}(
:none => :identity,
:log => :log10,
@@ -188,11 +188,11 @@ const _allGridSyms = [:x, :y, :z,
:all, :both, :on, :yes, :show,
:none, :off, :no, :hide]
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
hasgrid(arg::Void, letter) = false
hasgrid(arg::Nothing, letter) = false
hasgrid(arg::Bool, letter) = arg
function hasgrid(arg::Symbol, letter)
if arg in _allGridSyms
arg in (:all, :both, :on) || contains(string(arg), string(letter))
arg in (:all, :both, :on) || occursin(string(letter), string(arg))
else
warn("Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead.")
true
@@ -206,11 +206,11 @@ const _allShowaxisSyms = [:x, :y, :z,
:all, :both, :on, :yes, :show,
:off, :no, :hide]
const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)]
showaxis(arg::Void, letter) = false
showaxis(arg::Nothing, letter) = false
showaxis(arg::Bool, letter) = arg
function showaxis(arg::Symbol, letter)
if arg in _allGridSyms
arg in (:all, :both, :on, :yes) || contains(string(arg), string(letter))
arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg))
else
warn("Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead.")
true
@@ -301,6 +301,7 @@ const _plot_defaults = KW(
:inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are
# the parent layout and the relative bounding box of inset subplots
:dpi => DPI, # dots per inch for images, etc
:thickness_scaling => 1,
:display_type => :auto,
:extra_kwargs => KW(),
)
@@ -381,6 +382,7 @@ const _axis_defaults = KW(
:gridlinewidth => 0.5,
:tick_direction => :in,
:showaxis => true,
:widen => true,
)
const _suppress_warnings = Set{Symbol}([
@@ -652,6 +654,7 @@ function handleColors!(d::KW, arg, csym::Symbol)
d[csym] = c
end
return true
catch
end
false
end
@@ -1026,7 +1029,7 @@ function extractGroupArgs(vs::Tuple, args...)
end
# allow passing NamedTuples for a named legend entry
@require NamedTuples begin
@require NamedTuples = "73a701b4-84e1-5df0-88ff-1968ee2ee8dc" begin
legendEntryFromTuple(ns::NamedTuples.NamedTuple) =
join(["$k = $v" for (k, v) in zip(keys(ns), values(ns))], ", ")
@@ -1129,7 +1132,7 @@ function convertLegendValue(val::Symbol)
end
end
convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Void) = :none
convertLegendValue(val::Nothing) = :none
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
@@ -1473,26 +1476,19 @@ function _replace_linewidth(d::KW)
end
function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
pkg = plt.backend
globalIndex = d[:series_plotindex]
# add default values to our dictionary, being careful not to delete what we just added!
for (k,v) in _series_defaults
slice_arg!(d, d, k, v, commandIndex, false)
end
# this is how many series belong to this subplot
# plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list)
plotIndex = 0
for series in sp.series_list
if series[:primary]
plotIndex += 1
end
end
# plotIndex = count(series -> series[:primary], sp.series_list)
if get(d, :primary, true)
plotIndex += 1
end
return d
end
function _update_series_attributes!(d::KW, plt::Plot, sp::Subplot)
pkg = plt.backend
globalIndex = d[:series_plotindex]
plotIndex = _series_index(d, sp)
aliasesAndAutopick(d, :linestyle, _styleAliases, supported_styles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supported_markers(pkg), plotIndex)
@@ -1508,7 +1504,7 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
end
# update series color
d[:seriescolor] = getSeriesRGBColor.(d[:seriescolor], sp, plotIndex)
d[:seriescolor] = getSeriesRGBColor.(d[:seriescolor], Ref(sp), plotIndex)
# update other colors
for s in (:line, :marker, :fill)
@@ -1528,9 +1524,11 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
# update markerstrokecolor
d[:markerstrokecolor] = if d[:markerstrokecolor] == :match
plot_color(sp[:foreground_color_subplot], d[:markerstrokealpha])
plot_color(sp[:foreground_color_subplot])
elseif d[:markerstrokecolor] == :auto
getSeriesRGBColor.(d[:markercolor], sp, plotIndex)
else
getSeriesRGBColor(plot_color(d[:markerstrokecolor], d[:markerstrokealpha]), sp, plotIndex)
getSeriesRGBColor.(d[:markerstrokecolor], sp, plotIndex)
end
# if marker_z, fill_z or line_z are set, ensure we have a gradient
@@ -1560,3 +1558,19 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
_replace_linewidth(d)
d
end
function _series_index(d, sp)
idx = 0
for series in series_list(sp)
if series[:primary]
idx += 1
end
if series == d
return idx
end
end
if get(d, :primary, true)
idx += 1
end
return idx
end
+39 -25
View File
@@ -246,19 +246,17 @@ function get_ticks(axis::Axis)
ticks = ticks == :native ? :auto : ticks
dvals = axis[:discrete_values]
cv, dv = if !isempty(dvals)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in linspace(1, n, 15)]
elseif ticks == :all
1:n
elseif typeof(ticks) <: Int
Int[round(Int,i) for i in linspace(1, n, ticks)]
end
axis[:continuous_values][rng], dvals[rng]
elseif typeof(ticks) <: Symbol
if ispolar(axis.sps[1]) && axis[:letter] == :x
cv, dv = if typeof(ticks) <: Symbol
if !isempty(dvals)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in range(1, stop=n, length=15)]
else # if ticks == :all
1:n
end
axis[:continuous_values][rng], dvals[rng]
elseif ispolar(axis.sps[1]) && axis[:letter] == :x
#force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
else
@@ -266,8 +264,13 @@ function get_ticks(axis::Axis)
optimal_ticks_and_labels(axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
if !isempty(dvals) && typeof(ticks) <: Int
rng = Int[round(Int,i) for i in range(1, stop=length(dvals), length=ticks)]
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
end
elseif typeof(ticks) <: NTuple{2, Any}
# assuming we're passed (ticks, labels)
ticks
@@ -307,7 +310,7 @@ function expand_extrema!(axis::Axis, v::Number)
end
# these shouldn't impact the extrema
expand_extrema!(axis::Axis, ::Void) = axis[:extrema]
expand_extrema!(axis::Axis, ::Nothing) = axis[:extrema]
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
@@ -415,21 +418,23 @@ end
# -------------------------------------------------------------------------
# push the limits out slightly
function widen(lmin, lmax)
span = lmax - lmin
function widen(lmin, lmax, scale = :identity)
f, invf = scalefunc(scale), invscalefunc(scale)
span = f(lmax) - f(lmin)
# eps = NaNMath.max(1e-16, min(1e-2span, 1e-10))
eps = NaNMath.max(1e-16, 0.03span)
lmin-eps, lmax+eps
invf(f(lmin)-eps), invf(f(lmax)+eps)
end
# figure out if widening is a good idea. if there's a scale set it's too tricky,
# so lazy out and don't widen
# figure out if widening is a good idea.
const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d)
function default_should_widen(axis::Axis)
should_widen = false
if axis[:scale] == :identity && !is_2tuple(axis[:lims])
if !is_2tuple(axis[:lims])
for sp in axis.sps
for series in series_list(sp)
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
if series.d[:seriestype] in _widen_seriestypes
should_widen = true
end
end
@@ -438,6 +443,13 @@ function default_should_widen(axis::Axis)
should_widen
end
function round_limits(amin,amax)
scale = 10^(1-round(log10(amax - amin)))
amin = floor(amin*scale)/scale
amax = ceil(amax*scale)/scale
amin, amax
end
# using the axis extrema and limit overrides, return the min/max value for this axis
function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis))
ex = axis[:extrema]
@@ -466,8 +478,10 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
else
amin, amax
end
elseif should_widen
widen(amin, amax)
elseif should_widen && axis[:widen]
widen(amin, amax, axis[:scale])
elseif lims == :round
round_limits(amin,amax)
else
amin, amax
end
+4 -4
View File
@@ -1,3 +1,4 @@
using Pkg
struct NoBackend <: AbstractBackend end
@@ -134,8 +135,7 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
function pickDefaultBackend()
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
if env_default != ""
try
Pkg.installed(env_default) # this will error if not installed
if env_default in keys(Pkg.installed())
sym = Symbol(lowercase(env_default))
if haskey(_backendType, sym)
return backend(sym)
@@ -143,7 +143,7 @@ function pickDefaultBackend()
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
join(sort(_backends), "\n\t"))
end
catch
else
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not installed.")
end
end
@@ -152,7 +152,7 @@ function pickDefaultBackend()
# which one someone will want to use if they have the package installed...accounting for
# features, speed, and robustness
for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
if Pkg.installed(pkgstr) != nothing
if pkgstr in keys(Pkg.installed())
return backend(Symbol(lowercase(pkgstr)))
end
end
+8 -8
View File
@@ -9,7 +9,7 @@ TODO
* fix units in all visuals (e.g dotted lines, marker scale, surfaces)
=#
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "glvisualize.jl"))
end
@@ -80,7 +80,7 @@ function _initialize_backend(::GLVisualizeBackend; kw...)
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
const GL = Plots
GL = Plots
end
end
@@ -397,7 +397,7 @@ function gappy(x, ps)
return last(ps) - x
end
function ticks(points, resolution)
Float16[gappy(x, points) for x = linspace(first(points),last(points), resolution)]
Float16[gappy(x, points) for x = range(first(points), stop=last(points), length=resolution)]
end
@@ -901,12 +901,12 @@ function gl_boxplot(d, kw_args)
# filter 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))
q1,q2,q3,q4,q5 = quantile(values, range(0, stop=1, length=5))
# notch
n = Plots.notch_width(q2, q4, length(values))
# warn on inverted notches?
if notch && !warning && ( (q2>(q3-n)) || (q4<(q3+n)) )
warn("Boxplot's notch went outside hinges. Set notch to false.")
@warn("Boxplot's notch went outside hinges. Set notch to false.")
warning = true # Show the warning only one time
end
@@ -1005,7 +1005,7 @@ end
function scale_for_annotations!(series::Series, scaletype::Symbol = :pixels)
anns = series[:series_annotations]
if anns != nothing && !isnull(anns.baseshape)
if anns != nothing && anns.baseshape != nothing
# we use baseshape to overwrite the markershape attribute
# with a list of custom shapes for each
msw, msh = anns.scalefactor
@@ -1331,7 +1331,7 @@ end
function gl_surface(x,y,z, kw_args)
if isa(x, Range) && isa(y, Range)
if isa(x, AbstractRange) && isa(y, AbstractRange)
main = z
kw_args[:ranges] = (x, y)
else
@@ -1347,7 +1347,7 @@ function gl_surface(x,y,z, kw_args)
if get(kw_args, :wireframe, false)
points = map(Point3f0, zip(vec(x), vec(y), vec(z)))
faces = Cuint[]
idx = (i,j) -> sub2ind(size(z), i, j) - 1
idx = (i,j) -> CartesianIndices(size(z), i, j) - 1
for i=1:size(z,1), j=1:size(z,2)
i < size(z,1) && push!(faces, idx(i, j), idx(i+1, j))
+46 -47
View File
@@ -3,7 +3,7 @@
# significant contributions by @jheinen
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "gr.jl"))
end
@@ -144,7 +144,7 @@ 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_transparency(α::Real) = GR.settransparency(clamp(α, 0, 1))
function gr_set_transparency(::Void) end
function gr_set_transparency(::Nothing) end
# --------------------------------------------------------------------------------------
@@ -195,8 +195,8 @@ gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
function gr_inqtext(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.inqtextext(x, y, s[2:end-1])
elseif search(s, '\\') != 0 || contains(s, "10^{")
GR.inqmathtex(x, y, s[2:end-1])
elseif findfirst(isequal('\\'), s) != nothing || occursin("10^{", s)
GR.inqtextext(x, y, s)
else
GR.inqtext(x, y, s)
@@ -208,7 +208,7 @@ gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
function gr_text(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.mathtex(x, y, s[2:end-1])
elseif search(s, '\\') != 0 || contains(s, "10^{")
elseif findfirst(isequal('\\'), s) != nothing || occursin("10^{", s)
GR.textext(x, y, s)
else
GR.text(x, y, s)
@@ -317,7 +317,7 @@ function normalize_zvals(zv::AVec, clims::NTuple{2, <:Real})
if vmin == vmax
zeros(length(zv))
else
clamp.((zv - vmin) ./ (vmax - vmin), 0, 1)
clamp.((zv .- vmin) ./ (vmax .- vmin), 0, 1)
end
end
@@ -353,25 +353,18 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
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(get_markerstrokecolor(series, i))
gr_set_transparency(get_markerstrokealpha(series, i))
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])
else
# pick a color from the pre-loaded gradient
ci = round(Int, 1000 + _cycle(mz, i) * 255)
cfuncind(ci)
gr_set_transparency(_gr_gradient_alpha[ci-999])
end
# don't draw filled area if marker shape is 1D
# draw the shape - don't draw filled area if marker shape is 1D
if !(shape in (:hline, :vline, :+, :x))
cfunc(get_markercolor(series, i))
gr_set_transparency(get_markeralpha(series, i))
gr_draw_marker(x[i], y[i], msi, shape)
end
end
@@ -390,7 +383,7 @@ end
function gr_set_line(lw, style, c) #, a)
GR.setlinetype(gr_linetype[style])
w, h = gr_plot_size
GR.setlinewidth(max(0, lw / ((w + h) * 0.001)))
GR.setlinewidth(_gr_thickness_scaling[1] * max(0, lw / ((w + h) * 0.001)))
gr_set_linecolor(c) #, a)
end
@@ -403,6 +396,7 @@ end
# this stores the conversion from a font pointsize to "percentage of window height" (which is what GR uses)
const _gr_point_mult = 0.0018 * ones(1)
const _gr_thickness_scaling = 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,
@@ -491,7 +485,7 @@ function gr_colorbar(sp::Subplot, clims)
xmin, xmax = gr_xy_axislims(sp)[1:2]
gr_set_viewport_cmap(sp)
l = zeros(Int32, 1, 256)
l[1,:] = Int[round(Int, _i) for _i in linspace(1000, 1255, 256)]
l[1,:] = Int[round(Int, _i) for _i in range(1000, stop=1255, length=256)]
GR.setscale(0)
GR.setwindow(xmin, xmax, clims[1], clims[2])
GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l)
@@ -508,16 +502,16 @@ function gr_legend_pos(s::Symbol,w,h)
if str == "best"
str = "topright"
end
if contains(str,"right")
if occursin("right", str)
xpos = viewport_plotarea[2] - 0.05 - w
elseif contains(str,"left")
elseif occursin("left", str)
xpos = viewport_plotarea[1] + 0.11
else
xpos = (viewport_plotarea[2]-viewport_plotarea[1])/2 - w/2 +.04
end
if contains(str,"top")
if occursin("top", str)
ypos = viewport_plotarea[4] - 0.06
elseif contains(str,"bottom")
elseif occursin("bottom", str)
ypos = viewport_plotarea[3] + h + 0.06
else
ypos = (viewport_plotarea[4]-viewport_plotarea[3])/2 + h/2
@@ -537,7 +531,7 @@ const _gr_gradient_alpha = ones(256)
function gr_set_gradient(c)
grad = isa(c, ColorGradient) ? c : cgrad()
for (i,z) in enumerate(linspace(0, 1, 256))
for (i,z) in enumerate(range(0, stop=1, length=256))
c = grad[z]
GR.setcolorrep(999+i, red(c), green(c), blue(c))
_gr_gradient_alpha[i] = alpha(c)
@@ -549,6 +543,9 @@ end
function gr_display(plt::Plot, fmt="")
GR.clearws()
_gr_thickness_scaling[1] = plt[:thickness_scaling]
dpi_factor = plt[:dpi] / Plots.DPI
# collect some monitor/display sizes in meters and pixels
display_width_meters, display_height_meters, display_width_px, display_height_px = GR.inqdspsize()
display_width_ratio = display_width_meters / display_width_px
@@ -557,14 +554,6 @@ function gr_display(plt::Plot, fmt="")
# compute the viewport_canvas, normalized to the larger dimension
viewport_canvas = Float64[0,1,0,1]
w, h = plt[:size]
if !haskey(ENV, "PLOTS_TEST")
dpi_factor = plt[:dpi] / DPI
if fmt == "png"
dpi_factor *= 6
end
else
dpi_factor = 1
end
gr_plot_size[:] = [w, h]
if w > h
ratio = float(h) / w
@@ -587,7 +576,7 @@ function gr_display(plt::Plot, fmt="")
# update point mult
px_per_pt = px / pt
_gr_point_mult[1] = 1.5 * px_per_pt / max(h,w)
_gr_point_mult[1] = 1.5 * _gr_thickness_scaling[1] * px_per_pt / max(h,w)
# subplots:
for sp in plt.subplots
@@ -633,13 +622,14 @@ function gr_get_ticks_size(ticks, i)
end
function _update_min_padding!(sp::Subplot{GRBackend})
dpi = sp.plt[:thickness_scaling]
if !haskey(ENV, "GKSwstype")
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
ENV["GKSwstype"] = "svg"
end
end
# Add margin given by the user
leftpad = 2mm + sp[:left_margin]
leftpad = 4mm + sp[:left_margin]
toppad = 2mm + sp[:top_margin]
rightpad = 4mm + sp[:right_margin]
bottompad = 2mm + sp[:bottom_margin]
@@ -675,7 +665,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
if sp[:yaxis][:guide] != ""
leftpad += 4mm
end
sp.minpad = (leftpad, toppad, rightpad, bottompad)
sp.minpad = Tuple(dpi * [leftpad, toppad, rightpad, bottompad])
end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
@@ -725,6 +715,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if st == :heatmap
outside_ticks = true
for ax in (sp[:xaxis], sp[:yaxis])
v = series[ax[:letter]]
if diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
@warn("GR: heatmap only supported with equally spaced data.")
end
end
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)
@@ -776,7 +772,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# draw the axes
gr_set_font(tickfont(xaxis))
GR.setlinewidth(1)
GR.setlinewidth(sp.plt[:thickness_scaling])
if is3d(sp)
zmin, zmax = gr_lims(zaxis, true)
@@ -1046,10 +1042,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if series[:markershape] != :none
if series[:marker_z] != nothing
zmin, zmax = extrema(series[:marker_z])
GR.setspace(zmin, zmax, 0, 90)
end
gr_draw_markers(series, x, y, clims)
end
@@ -1059,7 +1051,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if typeof(series[:levels]) <: AbstractArray
h = series[:levels]
else
h = series[:levels] > 1 ? linspace(zmin, zmax, series[:levels]) : [(zmin + zmax) / 2]
h = series[:levels] > 1 ? range(zmin, stop=zmax, length=series[:levels]) : [(zmin + zmax) / 2]
end
if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
@@ -1077,7 +1069,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if cmap
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_viewport_cmap(sp)
l = (length(h) > 1) ? round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255) : Int32[1000, 1255]
l = (length(h) > 1) ? round.(Int32, 1000 .+ (h .- ignorenan_minimum(h)) ./ (ignorenan_maximum(h) - ignorenan_minimum(h)) .* 255) : Int32[1000, 1255]
GR.setwindow(xmin, xmax, zmin, zmax)
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
ztick = 0.5 * GR.tick(zmin, zmax)
@@ -1100,6 +1092,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :heatmap
xmin, xmax, ymin, ymax = xy_lims
zmin, zmax = clims
m, n = length(x), length(y)
xinds = sort(1:m, rev = xaxis[:flip])
yinds = sort(1:n, rev = yaxis[:flip])
z = reshape(reshape(z, m, n)[xinds, yinds], m*n)
GR.setspace(zmin, zmax, 0, 90)
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
colors = [plot_color(grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)], series[:fillalpha]) for zi=z]
@@ -1203,7 +1199,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :image
z = transpose_z(series, series[:z].surf, true)'
w, h = size(z)
w, h = length(x), length(y)
xinds = sort(1:w, rev = xaxis[:flip])
yinds = sort(1:h, rev = yaxis[:flip])
z = z[xinds, yinds]
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
if eltype(z) <: Colors.AbstractGray
grey = round.(UInt8, float(z) * 255)
@@ -1359,10 +1358,10 @@ const _gr_mimeformats = Dict(
"image/svg+xml" => "svg",
)
const _gr_wstype_default = @static if is_linux()
const _gr_wstype_default = @static if Sys.islinux()
"x11"
# "cairox11"
elseif is_apple()
elseif Sys.isapple()
"quartz"
else
"use_default"
@@ -1380,7 +1379,7 @@ for (mime, fmt) in _gr_mimeformats
ENV["GKS_FILEPATH"] = filepath
gr_display(plt, $fmt)
GR.emergencyclosegks()
write(io, readstring(filepath))
write(io, read(filepath, String))
rm(filepath)
if env != "0"
ENV["GKSwstype"] = env
+29 -22
View File
@@ -28,7 +28,7 @@ Read from .hdf5 file using:
- Should be reliable for archival purposes.
==#
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
end
@@ -39,7 +39,7 @@ struct HDF5PlotNative; end #Indentifies a data element that can natively be hand
struct HDF5CTuple; end #Identifies a "complex" tuple structure
mutable struct HDF5Plot_PlotRef
ref::Union{Plot, Void}
ref::Union{Plot, Nothing}
end
@@ -146,9 +146,9 @@ function _initialize_backend(::HDF5Backend)
export HDF5
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
const telem2str = Dict{String, Type}(
telem2str = Dict{String, Type}(
"NATIVE" => HDF5PlotNative,
"VOID" => Void,
"VOID" => Nothing,
"BOOL" => Bool,
"SYMBOL" => Symbol,
"TUPLE" => Tuple,
@@ -167,6 +167,7 @@ function _initialize_backend(::HDF5Backend)
# "PLOTTEXT" => PlotText,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
"SUBPLOT" => Subplot,
"NULLABLE" => Nullable,
)
@@ -239,10 +240,6 @@ end
# ----------------------------------------------------------------
_show(io::IO, mime::MIME"text/plain", plt::Plot{HDF5Backend}) = nothing #Don't show
# ----------------------------------------------------------------
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{HDF5Backend})
msg = "HDF5 interface does not support `display()` function."
@@ -318,9 +315,9 @@ function _hdf5plot_gwrite(grp, k::String, v::Array{Any})
warn("Cannot write Array: $k=$v")
end
=#
function _hdf5plot_gwrite(grp, k::String, v::Void)
function _hdf5plot_gwrite(grp, k::String, v::Nothing)
grp[k] = 0
_hdf5plot_writetype(grp, k, Void)
_hdf5plot_writetype(grp, k, Nothing)
end
function _hdf5plot_gwrite(grp, k::String, v::Bool)
grp[k] = Int(v)
@@ -347,7 +344,7 @@ end
function _hdf5plot_gwrite(grp, k::String, d::Dict)
# warn("Cannot write dict: $k=$d")
end
function _hdf5plot_gwrite(grp, k::String, v::Range)
function _hdf5plot_gwrite(grp, k::String, v::AbstractRange)
_hdf5plot_gwrite(grp, k, collect(v)) #For now
end
function _hdf5plot_gwrite(grp, k::String, v::ARGB{N0f8})
@@ -368,7 +365,7 @@ function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
sz = size(v)
for iter in eachindex(v)
coord = ind2sub(sz, iter)
coord = LinearIndices(sz, iter)
elem = v[iter]
idxstr = join(coord, "_")
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
@@ -407,15 +404,20 @@ function _hdf5plot_gwrite(grp, k::String, v::Axis)
_hdf5plot_writetype(grp, Axis)
return
end
#TODO: "Properly" support Nullable using _hdf5plot_writetype?
function _hdf5plot_gwrite(grp, k::String, v::Nullable)
if isnull(v)
_hdf5plot_gwrite(grp, k, nothing)
else
_hdf5plot_gwrite(grp, k, v.value)
end
return
function _hdf5plot_gwrite(grp, k::String, v::Surface)
grp = HDF5.g_create(grp, k)
_hdf5plot_gwrite(grp, "data2d", v.surf)
_hdf5plot_writetype(grp, Surface)
end
# #TODO: "Properly" support Nullable using _hdf5plot_writetype?
# function _hdf5plot_gwrite(grp, k::String, v::Nullable)
# if isnull(v)
# _hdf5plot_gwrite(grp, k, nothing)
# else
# _hdf5plot_gwrite(grp, k, v.value)
# end
# return
# end
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
#Currently no support for SeriesAnnotations
@@ -483,7 +485,7 @@ function _hdf5plot_readcount(grp) #Read directly from group
end
_hdf5plot_convert(T::Type{HDF5PlotNative}, v) = v
_hdf5plot_convert(T::Type{Void}, v) = nothing
_hdf5plot_convert(T::Type{Nothing}, v) = nothing
_hdf5plot_convert(T::Type{Bool}, v) = (v!=0)
_hdf5plot_convert(T::Type{Symbol}, v) = Symbol(v)
_hdf5plot_convert(T::Type{Tuple}, v) = tuple(v...) #With Vector{T<:Number}
@@ -528,7 +530,7 @@ function _hdf5plot_read(grp, k::String, T::Type{Array}, dtid) #ANY
result = Array{Any}(sz)
for iter in eachindex(result)
coord = ind2sub(sz, iter)
coord = LinearIndices(sz, iter)
idxstr = join(coord, "_")
result[iter] = _hdf5plot_read(grp, "v$idxstr")
end
@@ -577,6 +579,11 @@ function _hdf5plot_read(grp, k::String, T::Type{Axis}, dtid)
_hdf5plot_read(grp, kwlist)
return Axis([], kwlist)
end
function _hdf5plot_read(grp, k::String, T::Type{Surface}, dtid)
grp = HDF5.g_open(grp, k)
data2d = _hdf5plot_read(grp, "data2d")
return Surface(data2d)
end
function _hdf5plot_read(grp, k::String, T::Type{Subplot}, dtid)
grp = HDF5.g_open(grp, k)
idx = _hdf5plot_read(grp, "index")
+12 -13
View File
@@ -13,7 +13,7 @@ Add in functionality to Plots.jl:
:aspect_ratio,
=#
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "inspectdr.jl"))
end
@@ -90,24 +90,24 @@ end
# py_marker(markers::AVec) = map(py_marker, markers)
function _inspectdr_mapglyph(markers::AVec)
warn("Vectors of markers are currently unsupported in InspectDR.")
@warn("Vectors of markers are currently unsupported in InspectDR.")
_inspectdr_mapglyph(markers[1])
end
_inspectdr_mapglyphsize(v::Real) = v
function _inspectdr_mapglyphsize(v::Vector)
warn("Vectors of marker sizes are currently unsupported in InspectDR.")
@warn("Vectors of marker sizes are currently unsupported in InspectDR.")
_inspectdr_mapglyphsize(v[1])
end
_inspectdr_mapcolor(v::Colorant) = v
function _inspectdr_mapcolor(g::PlotUtils.ColorGradient)
warn("Color gradients are currently unsupported in InspectDR.")
@warn("Color gradients are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(g.colors[div(1+end,2)])
end
function _inspectdr_mapcolor(v::AVec)
warn("Vectors of colors are currently unsupported in InspectDR.")
@warn("Vectors of colors are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(v[div(1+end,2)])
end
@@ -166,13 +166,13 @@ function _initialize_backend(::InspectDRBackend; kw...)
export InspectDR
#Glyph used when plotting "Shape"s:
const INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
mutable struct InspecDRPlotRef
mplot::Union{Void, InspectDR.Multiplot}
gui::Union{Void, InspectDR.GtkPlot}
mplot::Union{Nothing, InspectDR.Multiplot}
gui::Union{Nothing, InspectDR.GtkPlot}
end
_inspectdr_getmplot(::Any) = nothing
@@ -347,8 +347,8 @@ end
# ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
const plot = sp.o
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
plot = sp.o
strip = plot.strips[1] #Only 1 strip supported with Plots.jl
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
@@ -406,7 +406,7 @@ end
# called just before updating layout bounding boxes... in case you need to prep
# for the calcs
function _before_layout_calcs(plt::Plot{InspectDRBackend})
const mplot = _inspectdr_getmplot(plt.o)
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot; return; end
mplot.title = plt[:plot_title]
@@ -506,7 +506,7 @@ const _inspectdr_mimeformats_nodpi = Dict(
# "application/postscript" => "ps", #TODO: support once Cairo supports PSSurface
"application/pdf" => "pdf"
)
_inspectdr_show(io::IO, mime::MIME, ::Void, w, h) =
_inspectdr_show(io::IO, mime::MIME, ::Nothing, w, h) =
throw(ErrorException("Cannot show(::IO, ...) plot - not yet generated"))
function _inspectdr_show(io::IO, mime::MIME, mplot, w, h)
InspectDR._show(io, mime, mplot, Float64(w), Float64(h))
@@ -523,7 +523,6 @@ for (mime, fmt) in _inspectdr_mimeformats_nodpi
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
end
end
_show(io::IO, mime::MIME"text/plain", plt::Plot{InspectDRBackend}) = nothing #Don't show
# ----------------------------------------------------------------
+69 -47
View File
@@ -2,17 +2,18 @@
# significant contributions by: @pkofod
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pgfplots.jl"))
end
const _pgfplots_attr = merge_with_base_supported([
:annotations,
# :background_color_legend,
:background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
# :foreground_color_text, :foreground_color_border,
# :foreground_color_legend,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
@@ -27,7 +28,7 @@ const _pgfplots_attr = merge_with_base_supported([
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar,
:fill_z, :line_z, :marker_z, #:levels,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
@@ -38,6 +39,7 @@ const _pgfplots_attr = merge_with_base_supported([
:tick_direction,
:framestyle,
:camera,
:contour_labels,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
@@ -148,6 +150,10 @@ function pgf_colormap(grad::ColorGradient)
end,", ")
end
pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
function pgf_fillstyle(d, i = 1)
cstr,a = pgf_color(get_fillcolor(d, i))
fa = get_fillalpha(d, i)
@@ -157,52 +163,56 @@ function pgf_fillstyle(d, i = 1)
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(d, i = 1)
cstr,a = pgf_color(get_linecolor(d, i))
la = get_linealpha(d, i)
if la != nothing
a = la
end
function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
cstr, a = pgf_color(plot_color(color, α))
"""
color = $cstr,
draw opacity=$a,
line width=$(get_linewidth(d, i)),
$(get(_pgfplots_linestyles, get_linestyle(d, i), "solid"))"""
draw opacity = $a,
line width = $linewidth,
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
end
function pgf_linestyle(d, i = 1)
lw = pgf_thickness_scaling(d) * get_linewidth(d, i)
lc = get_linecolor(d, i)
la = get_linealpha(d, i)
ls = get_linestyle(d, i)
return pgf_linestyle(lw, lc, la, ls)
end
function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
fs = fontsize * thickness_scaling
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
end
function pgf_marker(d, i = 1)
shape = _cycle(d[:markershape], i)
cstr, a = pgf_color(_cycle(d[:markercolor], i))
if d[:markeralpha] != nothing
a = _cycle(d[:markeralpha], i)
end
cstr_stroke, a_stroke = pgf_color(_cycle(d[:markerstrokecolor], i))
if d[:markerstrokealpha] != nothing
a_stroke = _cycle(d[:markerstrokealpha], i)
end
cstr, a = pgf_color(plot_color(get_markercolor(d, i), get_markeralpha(d, i)))
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(d, i), get_markerstrokealpha(d, i)))
"""
mark = $(get(_pgfplots_markers, shape, "*")),
mark size = $(0.5 * _cycle(d[:markersize], i)),
mark size = $(pgf_thickness_scaling(d) * 0.5 * _cycle(d[:markersize], i)),
mark options = {
color = $cstr_stroke, draw opacity = $a_stroke,
fill = $cstr, fill opacity = $a,
line width = $(_cycle(d[:markerstrokewidth], i)),
line width = $(pgf_thickness_scaling(d) * _cycle(d[:markerstrokewidth], i)),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, _cycle(d[:markerstrokestyle], i), "solid"))
}"""
end
function pgf_add_annotation!(o,x,y,val)
function pgf_add_annotation!(o, x, y, val, thickness_scaling = 1)
# Construct the style string.
# Currently supports color and orientation
cstr,a = pgf_color(val.font.color)
push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text
x, y,
style="""
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation)
"""))
x, y,
style="""
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation),
font=$(pgf_font(val.font.pointsize, thickness_scaling))
"""))
end
# --------------------------------------------------------------------------------------
@@ -221,10 +231,6 @@ function pgf_series(sp::Subplot, series::Series)
straightline_data(series)
elseif st == :shape
shape_data(series)
elseif d[:marker_z] != nothing
# If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation
d[:x], d[:y], d[:marker_z]
elseif ispolar(sp)
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
rad2deg.(theta), r
@@ -250,6 +256,8 @@ function pgf_series(sp::Subplot, series::Series)
func = if st == :histogram2d
PGFPlots.Histogram2
else
kw[:labels] = series[:contour_labels]
kw[:levels] = series[:levels]
PGFPlots.Contour
end
push!(series_collection, func(args...; kw...))
@@ -377,8 +385,9 @@ function pgf_axis(sp::Subplot, letter)
# axis guide
kw[Symbol(letter,:label)] = axis[:guide]
# Add ticklabel rotations
push!(style, "$(letter)ticklabel style={rotate = $(axis[:rotation])}")
# Add label font
cstr, α = pgf_color(plot_color(axis[:guidefontcolor]))
push!(style, string(letter, "label style = {font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}"))
# flip/reverse?
axis[:flip] && push!(style, "$letter dir=reverse")
@@ -417,11 +426,12 @@ function pgf_axis(sp::Subplot, letter)
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = String[begin
tick_labels = Vector{String}(length(ticks[2]))
for (i, label) in enumerate(ticks[2])
base, power = split(label, "^")
power = string("{", power, "}")
string(base, "^", power)
end for label in ticks[2]]
tick_labels[i] = string(base, "^", power)
end
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
elseif axis[:showaxis]
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
@@ -434,6 +444,9 @@ function pgf_axis(sp::Subplot, letter)
push!(style, string(letter, "ticklabels = {}"))
end
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
cstr, α = pgf_color(plot_color(axis[:tickfontcolor]))
push!(style, string(letter, "ticklabel style = {font = ", pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:tickfontrotation], "}"))
push!(style, string(letter, " grid style = {", pgf_linestyle(pgf_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]), "}"))
end
# framestyle
@@ -446,7 +459,7 @@ function pgf_axis(sp::Subplot, letter)
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {color = black, draw opacity=1.0, line width=0.5), solid}}"))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
end
if !axis[:showaxis]
@@ -454,6 +467,8 @@ function pgf_axis(sp::Subplot, letter)
end
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
else
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}"))
end
# return the style list and KW args
@@ -490,7 +505,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
bb = bbox(sp)
push!(style, """
xshift = $(left(bb).value)mm,
yshift = $(round((total_height - (bottom(bb))).value,2))mm,
yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""")
kw[:width] = "$(width(bb).value)mm"
@@ -498,6 +513,8 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
if sp[:title] != ""
kw[:title] = "$(sp[:title])"
cstr, α = pgf_color(plot_color(sp[:titlefontcolor]))
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
end
if sp[:aspect_ratio] in (1, :equal)
@@ -508,8 +525,13 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
if haskey(_pgfplots_legend_pos, legpos)
kw[:legendPos] = _pgfplots_legend_pos[legpos]
end
cstr, a = pgf_color(plot_color(sp[:background_color_legend]))
push!(style, string("legend style = {", pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid"), ",", "fill = $cstr,", "font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), "}"))
if is3d(sp)
if any(s[:seriestype] == :contour for s in series_list(sp))
kw[:view] = "{0}{90}"
kw[:colorbar] = !(sp[:colorbar] in (:none, :off, :hide, false))
elseif is3d(sp)
azim, elev = sp[:camera]
kw[:view] = "{$(azim)}{$(elev)}"
end
@@ -558,13 +580,13 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# add series annotations
anns = series[:series_annotations]
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt))
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt), pgf_thickness_scaling(series))
end
end
# add the annotations
for ann in sp[:annotations]
pgf_add_annotation!(o, locate_annotation(sp, ann...)...)
pgf_add_annotation!(o, locate_annotation(sp, ann...)..., pgf_thickness_scaling(sp))
end
@@ -586,7 +608,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
# read it into io
write(io, readstring(open(fn)))
write(io, read(open(fn), String))
# cleanup
PGFPlots.cleanup(plt.o)
@@ -595,7 +617,7 @@ end
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
fn = tempname()*".tex"
PGFPlots.save(fn, backend_object(plt), include_preamble=false)
write(io, readstring(open(fn)))
write(io, read(open(fn), String))
end
function _display(plt::Plot{PGFPlotsBackend})
+95 -81
View File
@@ -1,7 +1,7 @@
# https://plot.ly/javascript/getting-started
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotly.jl"))
end
@@ -263,19 +263,22 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
end
ax[:tickangle] = -axis[:rotation]
ax[:type] = plotly_scale(axis[:scale])
lims = axis_limits(axis)
axis[:ticks] != :native ? ax[:range] = map(scalefunc(axis[:scale]), lims) : nothing
if axis[:ticks] != :native || axis[:lims] != :auto
ax[:range] = map(scalefunc(axis[:scale]), lims)
end
if !(axis[:ticks] in (nothing, :none, false))
ax[:titlefont] = plotly_font(guidefont(axis))
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(tickfont(axis))
ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# flip
if axis[:flip]
ax[:autorange] = "reversed"
ax[:range] = reverse(ax[:range])
end
# ticks
@@ -325,9 +328,11 @@ function plotly_layout(plt::Plot)
d_out[:annotations] = KW[]
multiple_subplots = length(plt.subplots) > 1
for sp in plt.subplots
spidx = sp[:subplot_index]
x_idx, y_idx = plotly_link_indicies(plt, sp)
spidx = multiple_subplots ? sp[:subplot_index] : ""
x_idx, y_idx = multiple_subplots ? plotly_link_indicies(plt, sp) : ("", "")
# add an annotation for the title... positioned horizontally relative to plotarea,
# but vertically just below the top of the subplot bounding box
if sp[:title] != ""
@@ -385,6 +390,7 @@ function plotly_layout(plt::Plot)
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(legendfont(sp)),
:tracegroupgap => 0,
:x => xpos,
:y => ypos
)
@@ -444,7 +450,7 @@ function plotly_colorscale(c::AbstractVector{<:RGBA}, α)
if length(c) == 1
return [[0.0, rgba_string(plot_color(c[1], α))], [1.0, rgba_string(plot_color(c[1], α))]]
else
vals = linspace(0.0, 1.0, length(c))
vals = range(0.0, stop=1.0, length=length(c))
return [[vals[i], rgba_string(plot_color(c[i], α))] for i in eachindex(c)]
end
end
@@ -485,6 +491,21 @@ function plotly_close_shapes(x, y)
nanvcat(xs), nanvcat(ys)
end
function plotly_data(series::Series, letter::Symbol, data)
axis = series[:subplot][Symbol(letter, :axis)]
data = if axis[:ticks] == :native && data != nothing
plotly_native_data(axis, data)
else
data
end
if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe)
plotly_surface_data(series, data)
else
plotly_data(data)
end
end
plotly_data(v) = v != nothing ? collect(v) : v
plotly_data(surf::Surface) = surf.surf
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
@@ -493,6 +514,28 @@ plotly_surface_data(series::Series, a::AbstractVector) = a
plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false)
plotly_surface_data(series::Series, a::Surface) = plotly_surface_data(series, a.surf)
function plotly_native_data(axis::Axis, data::AbstractArray)
if !isempty(axis[:discrete_values])
construct_categorical_data(data, axis)
elseif axis[:formatter] in (datetimeformatter, dateformatter, timeformatter)
plotly_convert_to_datetime(data, axis[:formatter])
else
data
end
end
plotly_native_data(axis::Axis, a::Surface) = Surface(plotly_native_data(axis, a.surf))
function plotly_convert_to_datetime(x::AbstractArray, formatter::Function)
if formatter == datetimeformatter
map(xi -> replace(formatter(xi), "T", " "), x)
elseif formatter == dateformatter
map(xi -> string(formatter(xi), " 00:00:00"), x)
elseif formatter == timeformatter
map(xi -> string(Dates.Date(Dates.now()), " ", formatter(xi)), x)
else
error("Invalid DateTime formatter. Expected Plots.datetime/date/time formatter but got $formatter")
end
end
#ensures that a gradient is called if a single color is supplied where a gradient is needed (e.g. if a series recipe defines marker_z)
as_gradient(grad::ColorGradient, α) = grad
as_gradient(grad, α) = cgrad(alpha = α)
@@ -513,20 +556,17 @@ function plotly_series(plt::Plot, series::Series)
d_out[:yaxis] = "y$(y_idx)"
d_out[:showlegend] = should_add_to_legend(series)
x, y, z = map(letter -> (axis = sp[Symbol(letter, :axis)];
if axis[:ticks] == :native && !isempty(axis[:discrete_values])
axis[:discrete_values]
elseif st in (:heatmap, :contour, :surface, :wireframe)
plotly_surface_data(series, series[letter])
else
plotly_data(series[letter])
end), (:x, :y, :z))
if st == :straightline
x, y = straightline_data(series)
z = series[:z]
else
x, y, z = series[:x], series[:y], series[:z]
end
x, y, z = (plotly_data(series, letter, data)
for (letter, data) in zip((:x, :y, :z), (x, y, z))
)
d_out[:name] = series[:label]
isscatter = st in (:scatter, :scatter3d, :scattergl)
@@ -547,6 +587,8 @@ function plotly_series(plt::Plot, series::Series)
return plotly_series_segments(series, d_out, x, y, z)
elseif st == :heatmap
x = heatmap_edges(x, sp[:xaxis][:scale])
y = heatmap_edges(y, sp[:yaxis][:scale])
d_out[:type] = "heatmap"
d_out[:x], d_out[:y], d_out[:z] = x, y, z
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
@@ -595,31 +637,17 @@ function plotly_series(plt::Plot, series::Series)
# add "marker"
if hasmarker
inds = eachindex(x)
d_out[:marker] = KW(
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
# :opacity => series[:markeralpha],
:size => 2 * series[:markersize],
# :color => rgba_string(series[:markercolor]),
:size => 2 * _cycle(series[:markersize], inds),
:color => rgba_string.(plot_color.(get_markercolor.(series, inds), get_markeralpha.(series, inds))),
:line => KW(
:color => _cycle(rgba_string.(series[:markerstrokecolor]),eachindex(series[:x])),
:width => series[:markerstrokewidth],
:color => rgba_string.(plot_color.(get_markerstrokecolor.(series, inds), get_markerstrokealpha.(series, inds))),
:width => _cycle(series[:markerstrokewidth], inds),
),
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
if series[:marker_z] == nothing
d_out[:marker][:color] = _cycle(rgba_string.(series[:markercolor]),eachindex(series[:x]))
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
# grad = as_gradient(series[:markercolor], series[:markeralpha])
cmin, cmax = get_clims(sp)
# 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)
d_out[:marker][:color] = [clamp(zi, cmin, cmax) for zi in series[:marker_z]]
d_out[:marker][:cmin] = cmin
d_out[:marker][:cmax] = cmax
d_out[:marker][:colorscale] = plotly_colorscale(series[:markercolor], series[:markeralpha])
d_out[:marker][:showscale] = hascolorbar(sp)
end
end
plotly_polar!(d_out, series)
@@ -637,18 +665,22 @@ function plotly_series_shapes(plt::Plot, series::Series)
# these are the axes that the series should be mapped to
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
base_d = KW()
base_d[:xaxis] = "x$(x_idx)"
base_d[:yaxis] = "y$(y_idx)"
base_d[:name] = series[:label]
# base_d[:legendgroup] = series[:label]
d_base = KW(
:xaxis => "x$(x_idx)",
:yaxis => "y$(y_idx)",
:name => series[:label],
:legendgroup => series[:label],
)
x, y = (plotly_data(series, letter, data)
for (letter, data) in zip((:x, :y), shape_data(series))
)
x, y = shape_data(series)
for (i,rng) in enumerate(segments)
length(rng) < 2 && continue
# to draw polygons, we actually draw lines with fill
d_out = merge(base_d, KW(
d_out = merge(d_base, KW(
:type => "scatter",
:mode => "lines",
:x => vcat(x[rng], x[rng[1]]),
@@ -669,9 +701,11 @@ function plotly_series_shapes(plt::Plot, series::Series)
d_outs[i] = d_out
end
if series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, base_d, :fill))
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
elseif series[:line_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, base_d, :line))
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
elseif series[:marker_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
end
d_outs
end
@@ -689,10 +723,11 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
d_outs = Vector{KW}((hasfillrange ? 2 : 1 ) * length(segments))
for (i,rng) in enumerate(segments)
length(rng) < 2 && continue
!isscatter && length(rng) < 2 && continue
d_out = deepcopy(d_base)
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
d_out[:legendgroup] = series[:label]
# set the type
if st in (:path, :scatter, :scattergl, :straightline)
@@ -726,30 +761,15 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
# add "marker"
if hasmarker
d_out[:marker] = KW(
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
:symbol => get(_plotly_markers, _cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
# :opacity => series[:markeralpha],
:size => 2 * series[:markersize],
# :color => rgba_string(series[:markercolor]),
:size => 2 * _cycle(series[:markersize], i),
:color => rgba_string(plot_color(get_markercolor(series, i), get_markeralpha(series, i))),
:line => KW(
:color => _cycle(rgba_string.(series[:markerstrokecolor]), eachindex(rng)),
:width => series[:markerstrokewidth],
:color => rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))),
:width => _cycle(series[:markerstrokewidth], i),
),
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
if series[:marker_z] == nothing
d_out[:marker][:color] = _cycle(rgba_string.(series[:markercolor]), eachindex(rng))
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
# grad = as_gradient(series[:markercolor], series[:markeralpha])
cmin, cmax = get_clims(sp)
# 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)
d_out[:marker][:color] = [clamp(zi, cmin, cmax) for zi in _cycle(series[:marker_z], rng)]
d_out[:marker][:cmin] = cmin
d_out[:marker][:cmax] = cmax
d_out[:marker][:colorscale] = plotly_colorscale(series[:markercolor], series[:markeralpha])
d_out[:marker][:showscale] = hascolorbar(sp)
end
end
# add "line"
@@ -769,7 +789,7 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, series[:hover])
plotly_hover!(d_out, _cycle(series[:hover], rng))
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
@@ -785,14 +805,14 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
series[:fillrange] = (f1, f2)
end
if isa(series[:fillrange], AbstractVector)
d_out_fillrange[:y] = series[:fillrange]
d_out_fillrange[:y] = series[:fillrange][rng]
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
else
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
# is the series that will do the filling
d_out_fillrange[:x], d_out_fillrange[:y] =
concatenate_fillrange(x[rng], series[:fillrange][rng])
fillrng = Tuple(series[:fillrange][i][rng] for i in 1:2)
d_out_fillrange[:x], d_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
d_out_fillrange[:line][:width] = 0
delete!(d_out, :fill)
delete!(d_out, :fillcolor)
@@ -808,6 +828,8 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
elseif series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
elseif series[:marker_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
end
d_outs
@@ -818,6 +840,7 @@ function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
cmin, cmax = get_clims(series[:subplot])
d_out[:showlegend] = false
d_out[:type] = is3d(series) ? :scatter3d : :scatter
d_out[:hoverinfo] = :none
d_out[:mode] = :markers
d_out[:x], d_out[:y] = [series[:x][1]], [series[:y][1]]
if is3d(series)
@@ -826,6 +849,7 @@ function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
# 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)
d_out[:marker] = KW(
:size => 0,
:opacity => 0,
:color => [0.5],
:cmin => cmin,
:cmax => cmax,
@@ -904,17 +928,7 @@ end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
# show_png_from_html(io, plt)
error("png output from the plotly backend is not supported. Please use plotlyjs instead.")
end
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend})
error("svg output from the plotly backend is not supported. Please use plotlyjs instead.")
end
function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
prepare_output(plt)
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, html_head(plt) * html_body(plt))
end
+9 -4
View File
@@ -1,5 +1,5 @@
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
end
# https://github.com/spencerlyon2/PlotlyJS.jl
@@ -88,8 +88,7 @@ end
# ----------------------------------------------------------------
function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
prepare_output(plt)
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else
@@ -121,6 +120,12 @@ function _display(plt::Plot{PlotlyJSBackend})
end
end
@require WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" begin
function WebIO.render(plt::Plot{PlotlyJSBackend})
prepare_output(plt)
WebIO.render(plt.o)
end
end
function closeall(::PlotlyJSBackend)
if !isplotnull() && isa(current().o, PlotlyJS.SyncPlot)
+53 -49
View File
@@ -1,7 +1,7 @@
# https://github.com/stevengj/PyPlot.jl
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pyplot.jl"))
end
@@ -82,21 +82,21 @@ function _initialize_backend(::PyPlotBackend)
append!(Base.Multimedia.displays, otherdisplays)
export PyPlot
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")
pycolors = PyPlot.pyimport("matplotlib.colors")
pypath = PyPlot.pyimport("matplotlib.path")
mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
pypatches = PyPlot.pyimport("matplotlib.patches")
pyfont = PyPlot.pyimport("matplotlib.font_manager")
pyticker = PyPlot.pyimport("matplotlib.ticker")
pycmap = PyPlot.pyimport("matplotlib.cm")
pynp = PyPlot.pyimport("numpy")
pynp["seterr"](invalid="ignore")
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
const pycollections = PyPlot.pyimport("matplotlib.collections")
const pyart3d = PyPlot.art3D
pytransforms = PyPlot.pyimport("matplotlib.transforms")
pycollections = PyPlot.pyimport("matplotlib.collections")
pyart3d = PyPlot.art3D
# "support" matplotlib v1.5
const set_facecolor_sym = if PyPlot.version < v"2"
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
@@ -395,14 +395,14 @@ function py_bbox_title(ax)
end
function py_dpi_scale(plt::Plot{PyPlotBackend}, ptsz)
ptsz * plt[:dpi] / DPI
ptsz
end
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{PyPlotBackend})
w,h = map(px2inch, plt[:size])
w,h = map(px2inch, Tuple(s * plt[:dpi] / Plots.DPI for s in plt[:size]))
# # reuse the current figure?
fig = if plt[:overwrite_figure]
@@ -570,12 +570,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if series[:markershape] != :none && st in (:path, :scatter, :path3d,
:scatter3d, :steppre, :steppost,
:bar)
if series[:marker_z] == nothing
extrakw[:c] = series[:markershape] in (:+, :x, :hline, :vline) ? py_markerstrokecolor(series) : py_color_fix(py_markercolor(series), x)
markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] != nothing
py_color(plot_color.(get_markercolor.(series, eachindex(x)), get_markeralpha.(series, eachindex(x))))
else
extrakw[:c] = convert(Vector{Float64}, series[:marker_z])
extrakw[:cmap] = py_markercolormap(series)
py_color(plot_color(series[:markercolor], series[:markeralpha]))
end
extrakw[:c] = py_color_fix(markercolor, x)
xyargs = if st == :bar && !isvertical(series)
(y, x)
else
@@ -591,11 +591,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
msc = py_markerstrokecolor(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)
else
extrakw[:c]
end
extrakw[:c] = _cycle(markercolor, i)
push!(handle, ax[:scatter](_cycle(x,i), _cycle(y,i);
label = series[:label],
@@ -638,6 +634,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if st in (:contour, :contour3d)
z = transpose_z(series, z.surf)
if typeof(x)<:Plots.Surface
x = Plots.transpose_z(series, x.surf)
end
if typeof(y)<:Plots.Surface
y = Plots.transpose_z(series, y.surf)
end
if st == :contour3d
extrakw[:extend3d] = true
@@ -677,8 +679,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if typeof(z) <: AbstractMatrix || typeof(z) <: Surface
x, y, z = map(Array, (x,y,z))
if !ismatrix(x) || !ismatrix(y)
x = repmat(x', length(y), 1)
y = repmat(y, 1, length(series[:x]))
x = repeat(x', length(y), 1)
y = repeat(y, 1, length(series[:x]))
end
z = transpose_z(series, z)
if st == :surface
@@ -835,9 +837,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
n = length(dim1)
args = if typeof(fillrange) <: Union{Real, AVec}
dim1, expand_data(fillrange, n), dim2
dim1, _cycle(fillrange, rng), dim2
elseif is_2tuple(fillrange)
dim1, expand_data(fillrange[1], n), expand_data(fillrange[2], n)
dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng)
end
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
@@ -917,7 +919,7 @@ function py_set_scale(ax, axis::Axis)
"linear"
else
kw[Symbol(:base,letter)] = if scale == :ln
e
elseif scale == :log2
2
elseif scale == :log10
@@ -953,10 +955,10 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
w, h = plt[:size]
fig = plt.o
fig[:clear]()
dpi = plt[:dpi]
fig[:set_size_inches](w/dpi, h/dpi, forward = true)
dpi = plt[:thickness_scaling] * plt[:dpi]
fig[:set_size_inches](w/DPI/plt[:thickness_scaling], h/DPI/plt[:thickness_scaling], forward = true)
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
fig[:set_dpi](dpi)
fig[:set_dpi](plt[:dpi])
# resize the window
PyPlot.plt[:get_current_fig_manager]()[:resize](w, h)
@@ -1014,10 +1016,16 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
kw[:ticks] = locator
kw[:format] = formatter
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
elseif any(colorbar_series[attr] != nothing for attr in (:line_z, :fill_z))
elseif any(colorbar_series[attr] != nothing for attr in (:line_z, :fill_z, :marker_z))
cmin, cmax = get_clims(sp)
norm = pycolors[:Normalize](vmin = cmin, vmax = cmax)
f = colorbar_series[:line_z] != nothing ? py_linecolormap : py_fillcolormap
f = if colorbar_series[:line_z] != nothing
py_linecolormap
elseif colorbar_series[:fill_z] != nothing
py_fillcolormap
else
py_markercolormap
end
cmap = pycmap[:ScalarMappable](norm = norm, cmap = f(colorbar_series))
cmap[:set_array]([])
handle = cmap
@@ -1201,7 +1209,9 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
rightpad += sp[:right_margin]
bottompad += sp[:bottom_margin]
sp.minpad = (leftpad, toppad, rightpad, bottompad)
dpi_factor = sp.plt[:thickness_scaling] * Plots.DPI / sp.plt[:dpi]
sp.minpad = Tuple(dpi_factor .* [leftpad, toppad, rightpad, bottompad])
end
@@ -1262,8 +1272,8 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
linewidth = py_dpi_scale(plt, clamp(get_linewidth(series), 0, 5)),
linestyle = py_linestyle(:path, get_linestyle(series)),
marker = py_marker(series[:markershape]),
markeredgecolor = py_markerstrokecolor(series),
markerfacecolor = series[:marker_z] == nothing ? py_markercolor(series) : py_color(series[:markercolor][0.5])
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
)
else
series[:serieshandle][1]
@@ -1278,23 +1288,17 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
labels,
loc = get(_pyplot_legend_pos, leg, "best"),
scatterpoints = 1,
fontsize = py_dpi_scale(plt, sp[:legendfontsize])
# family = sp[:legendfont].family
# framealpha = 0.6
fontsize = py_dpi_scale(plt, sp[:legendfontsize]),
facecolor = py_color(sp[:background_color_legend]),
edgecolor = py_color(sp[:foreground_color_legend]),
framealpha = alpha(plot_color(sp[:background_color_legend])),
)
leg[:set_zorder](1000)
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
fgcolor = py_color(sp[:foreground_color_legend])
lfcolor = py_color(sp[:legendfontcolor])
for txt in leg[:get_texts]()
PyPlot.plt[:setp](txt, color = lfcolor, family = sp[:legendfontfamily])
PyPlot.plt[:setp](txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily])
end
# set some legend properties
frame = leg[:get_frame]()
frame[set_facecolor_sym](py_color(sp[:background_color_legend]))
frame[:set_edgecolor](fgcolor)
end
end
end
@@ -1356,7 +1360,7 @@ for (mime, fmt) in _pyplot_mimeformats
# figsize = map(px2inch, plt[:size]),
facecolor = fig[:get_facecolor](),
edgecolor = "none",
dpi = plt[:dpi]
dpi = plt[:dpi] * plt[:thickness_scaling]
)
end
end
+3 -3
View File
@@ -1,7 +1,7 @@
# https://github.com/Evizero/UnicodePlots.jl
@require Revise begin
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
end
@@ -183,7 +183,7 @@ function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
gui(plt)
# @osx_only begin
@static if is_apple()
@static if Sys.isapple()
# BEGIN HACK
# wait while the plot gets drawn
@@ -212,7 +212,7 @@ end
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
map(show, plt.o)
foreach(x -> show(io, x), plt.o)
nothing
end
+6 -6
View File
@@ -2,8 +2,8 @@
# NOTE: backend should implement `html_body` and `html_head`
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
end
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
@@ -23,16 +23,16 @@ function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr
end
function open_browser_window(filename::AbstractString)
@static if is_apple()
@static if Sys.isapple()
return run(`open $(filename)`)
end
@static if is_linux() || is_bsd() # is_bsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
@static if Sys.islinux() || Sys.isbsd() # Sys.isbsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
return run(`xdg-open $(filename)`)
end
@static if is_windows()
@static if Sys.iswindows()
return run(`$(ENV["COMSPEC"]) /c start "" "$(filename)"`)
end
warn("Unknown OS... cannot open browser window.")
@warn("Unknown OS... cannot open browser window.")
end
function write_temp_html(plt::AbstractPlot)
+16 -12
View File
@@ -58,7 +58,7 @@ end
"get an array of tuples of points on a circle with radius `r`"
function partialcircle(start_θ, end_θ, n = 20, r=1)
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)"
@@ -68,7 +68,8 @@ function weave(x,y; ordering = Vector[x,y])
while !done
for o in ordering
try
push!(ret, shift!(o))
push!(ret, popfirst!(o))
catch
end
end
done = isempty(x) && isempty(y)
@@ -388,6 +389,7 @@ function stroke(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
@@ -420,6 +422,7 @@ function brush(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
@@ -438,16 +441,16 @@ end
mutable struct SeriesAnnotations
strs::AbstractVector # the labels/names
font::Font
baseshape::Nullable
baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
scalefactor::Tuple
end
function series_annotations(strs::AbstractVector, args...)
fnt = font()
shp = Nullable{Any}()
shp = nothing
scalefactor = (1,1)
for arg in args
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
shp = Nullable(arg)
shp = arg
elseif isa(arg, Font)
fnt = arg
elseif isa(arg, Symbol) && haskey(_shapes, arg)
@@ -468,7 +471,7 @@ function series_annotations(strs::AbstractVector, args...)
SeriesAnnotations(strs, fnt, shp, scalefactor)
end
series_annotations(anns::SeriesAnnotations) = anns
series_annotations(::Void) = nothing
series_annotations(::Nothing) = nothing
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
anns = series[:series_annotations]
@@ -483,12 +486,13 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# end
# @show msw msh
if anns != nothing && !isnull(anns.baseshape)
if anns != nothing && anns.baseshape != nothing
# we use baseshape to overwrite the markershape attribute
# with a list of custom shapes for each
msw,msh = anns.scalefactor
msize = Float64[]
shapes = Shape[begin
shapes = Vector{Shape}(length(anns.strs))
for i in eachindex(anns.strs)
str = _cycle(anns.strs,i)
# get the width and height of the string (in mm)
@@ -506,8 +510,8 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = _cycle(get(anns.baseshape),i)
shape = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end for i=1:length(anns.strs)]
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end
series[:markershape] = shapes
series[:markersize] = msize
end
@@ -531,7 +535,7 @@ function Base.next(ea::EachAnn, i)
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
end
annotations(::Void) = []
annotations(::Nothing) = []
annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
annotations(sa::SeriesAnnotations) = sa
@@ -747,7 +751,7 @@ end
@deprecate curve_points coords
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, range(range..., stop=n, length=50))
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
# may create a loop if necessary. Assumes the view is [0,1]
+2 -2
View File
@@ -72,7 +72,7 @@ is_subplot_supported(::BokehBackend) = false
function _initialize_backend(::BokehBackend; kw...)
@eval begin
warn("Bokeh is no longer supported... many features will likely be broken.")
@warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
@@ -196,7 +196,7 @@ end
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
# TODO: write a png to io
warn("mime png not implemented")
@warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
+3 -3
View File
@@ -244,7 +244,7 @@ function addToGadflyLegend(plt::Plot, d::KW)
# add the legend if needed
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
pushfirst!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
end
# now add the series to the legend
@@ -334,8 +334,8 @@ end
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(d[:y])]
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
# cs = collect(repeat(csindices', 2, 1))[1:end-1]
# grp = collect(repeat((1:length(d[:y]))', 2, 1))[1:end-1]
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
# colorgroup = [(:linecolor, cs), (:group, grp)]
+2 -2
View File
@@ -31,7 +31,7 @@ is_subplot_supported(::QwtBackend) = true
function _initialize_backend(::QwtBackend; kw...)
@eval begin
warn("Qwt is no longer supported... many features will likely be broken.")
@warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
@@ -142,7 +142,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
w[:setAxisScale](axisid, lims...)
end
if typeof(ticks) <: Range
if typeof(ticks) <: AbstractRange
if isx
plt.o.autoscale_x = false
else
+1 -1
View File
@@ -34,7 +34,7 @@ is_subplot_supported(::WinstonBackend) = false
function _initialize_backend(::WinstonBackend; kw...)
@eval begin
# ENV["WINSTON_OUTPUT"] = "gtk"
warn("Winston is no longer supported... many features will likely be broken.")
@warn("Winston is no longer supported... many features will likely be broken.")
import Winston, Gtk
export Winston, Gtk
end
+1 -1
View File
@@ -19,7 +19,7 @@
# work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
function sample_evenly(v::AVec, n::Integer = length(v))
idx = Int[round(Int, x) for x in linspace(1, length(v), n)]
idx = Int[round(Int, x) for x in range(1, stop=length(v), length=n)]
v[idx]
end
+13 -13
View File
@@ -13,15 +13,15 @@ function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
values = if values != nothing
values
elseif scale in (:log, :log10)
log10(linspace(1,10,30))
log10(range(1, stop=10, length=30))
elseif scale == :log2
log2(linspace(1,2,30))
log2(range(1, stop=2, length=30))
elseif scale == :ln
log(linspace(1,pi,30))
log(range(1, stop=pi, length=30))
elseif scale in (:exp, :exp10)
(exp10(linspace(0,1,30)) - 1) / 9
(exp10(range(0, stop=1, length=30)) - 1) / 9
else
linspace(0, 1, length(colors))
range(0, stop=1, length=length(colors))
end
ColorGradient(colors, values)
end
@@ -51,7 +51,7 @@ convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
convertColor(v::Void) = RGBA(0,0,0,0)
convertColor(v::Nothing) = RGBA(0,0,0,0)
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
function convertColor(c, α::Real)
@@ -59,7 +59,7 @@ function convertColor(c, α::Real)
RGBA(RGB(getColor(c)), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::Void) = convertColor(c)
convertColor(c, α::Nothing) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
@@ -113,7 +113,7 @@ struct ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing) where S<:Real
function ColorGradient(cs::AVec, vals::AVec{S} = range(0, stop=1, length=length(cs)); alpha = nothing) where S<:Real
if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals))
end
@@ -124,9 +124,9 @@ struct ColorGradient <: ColorScheme
# new(convertColor(cs,alpha), vs)
# interpolate the colors for each value
vals = merge(linspace(0, 1, length(cs)), vals)
vals = merge(range(0, stop=1, length=length(cs)), vals)
grad = ColorGradient(cs)
cs = [getColorZ(grad, z) for z in linspace(0, 1, length(vals))]
cs = [getColorZ(grad, z) for z in range(0, stop=1, length=length(vals))]
new(convertColor(cs, alpha), vals)
end
end
@@ -142,7 +142,7 @@ function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
cs = _gradients[s]
if vals == 0:0
vals = linspace(0, 1, length(cs))
vals = range(0, stop=1, length=length(cs))
end
ColorGradient(cs, vals; kw...)
end
@@ -247,7 +247,7 @@ ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Color
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
convertColor(c::ColorWrapper, α::Void) = c.c
convertColor(c::ColorWrapper, α::Nothing) = c.c
# --------------------------------------------------------------
@@ -332,7 +332,7 @@ function generate_colorgradient(bgcolor = colorant"white";
seed_colors,
lchoices=Float64[lightness],
cchoices=Float64[chroma],
hchoices=linspace(0, 340, 20)
hchoices=range(0, stop=340, length=20)
)[2:end]
gradient_from_list(colors)
end
+8 -8
View File
@@ -10,7 +10,7 @@ const FuncOrFuncs = Union{Function, AVec{Function}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
# missing
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
convertToAnyVector(v::Nothing, d::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
@@ -65,19 +65,19 @@ end
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1)
compute_x(x::Nothing, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z::Nothing) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
@@ -92,8 +92,8 @@ nobigs(v) = v
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
compute_xyz(x::Nothing, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
+20 -20
View File
@@ -29,7 +29,7 @@ animation.
[:(begin
p = plot([sin,cos], zeros(0), leg=false)
anim = Animation()
for x in linspace(0, 10π, 100)
for x in range(0, stop=10π, length=100)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
@@ -52,7 +52,7 @@ the `z` argument to turn on series gradients.
[:(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,
scatter!(y, zcolor=abs.(y.-0.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y.-0.5).+4,
lab="grad")
end)]
),
@@ -69,7 +69,7 @@ the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`
y = rand(20,3)
plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2),
leg=false)
hline!(mean(y,1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
hline!(mean(y, dims = 1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
vline!([5,10])
title!("TITLE")
yaxis!("YLABEL", :log10)
@@ -145,7 +145,7 @@ styles = filter(s -> s in Plots.supported_styles(),
[:solid, :dash, :dot, :dashdot, :dashdotdot])
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20,n),1)
y = cumsum(randn(20,n), dims = 1)
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
),
@@ -156,8 +156,8 @@ PlotExample("Marker types",
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(reshape(reverse(x),1,:), n, 1)
x = range(0, stop=10, length=n+2)[2:end-1]
y = repeat(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)]
),
@@ -202,7 +202,7 @@ plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbo
PlotExample("",
"",
[:(begin
srand(111)
Random.srand(111)
plot!(Plots.fakedata(100,10))
end)]
),
@@ -215,7 +215,7 @@ subsequently create a :path series with the appropriate line segments.
""",
[:(begin
n=20
hgt=rand(n)+1
hgt=rand(n).+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
@@ -238,7 +238,7 @@ y = rand(10)
plot(y, annotations = (3,y[3],text("this is #3",:left)), leg=false)
annotate!([(5, y[5], text("this is #5",16,:red,:center)),
(10, y[10], text("this is #10",:right,20,"courier"))])
scatter!(linspace(2,8,6), rand(6), marker=(50,0.2,:orange),
scatter!(range(2, stop=8, length=6), rand(6), marker=(50,0.2,:orange),
series_annotations = ["series","annotations","map","to","series",
text("data",:green)])
end)]
@@ -254,7 +254,7 @@ verts = [(-1.0,1.0),(-1.28,0.6),(-0.2,-1.4),(0.2,-1.4),(1.28,0.6),(1.0,1.0),
(-1.0,1.0),(-0.2,-0.6),(0.0,-0.2),(-0.4,0.6),(1.28,0.6),(0.2,-1.4),
(-0.2,-1.4),(0.6,0.2),(-0.2,0.2),(0.0,-0.2),(0.2,0.2),(-0.2,-0.6)]
x = 0.1:0.2:0.9
y = 0.7rand(5)+0.15
y = 0.7rand(5).+0.15
plot(x, y, line = (3,:dash,:lightblue), marker = (Shape(verts),30,RGBA(0,0,0,0.2)),
bg=:pink, fg=:darkblue, xlim = (0,1), ylim=(0,1), leg=false)
end)]
@@ -269,8 +269,8 @@ unfilled contour from a matrix.
x = 1:0.5:20
y = 1:0.5:10
f(x,y) = (3x+y^2)*abs(sin(x)+cos(y))
X = repmat(reshape(x,1,:), length(y), 1)
Y = repmat(y, 1, length(x))
X = repeat(reshape(x,1,:), length(y), 1)
Y = repeat(y, 1, length(x))
Z = map(f, X, Y)
p1 = contour(x, y, f, fill=true)
p2 = contour(x, y, Z)
@@ -291,7 +291,7 @@ PlotExample("3D",
"",
[:(begin
n = 100
ts = linspace(0,8π,n)
ts = range(0, stop=8π, length=n)
x = ts .* map(cos,ts)
y = 0.1ts .* map(sin,ts)
z = 1:n
@@ -323,7 +323,7 @@ PlotExample("Groups and Subplots",
PlotExample("Polar Plots",
"",
[:(begin
Θ = linspace(0,1.5π,100)
Θ = range(0, stop=1.5π, length=100)
r = abs.(0.1randn(100)+sin.(3Θ))
plot(Θ, r, proj=:polar, m=2)
end)]
@@ -368,7 +368,7 @@ PlotExample("Animation with subplots",
plot(log,1,xlims=(1,10π),ylims=(0,5),leg=false),layout=l)
anim = Animation()
for x = linspace(1,10π,100)
for x = range(1, stop=10π, length=100)
plot(push!(p,x,Float64[sin(x),cos(x),atan(x),cos(x),log(x)]))
frame(anim)
end
@@ -377,8 +377,8 @@ PlotExample("Animation with subplots",
PlotExample("Spy",
"""
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
various different nonzero values, a colorbar is added. The colorbar can be disabled with
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
various different nonzero values, a colorbar is added. The colorbar can be disabled with
`legend = nothing`.
""",
[:(begin
@@ -419,10 +419,10 @@ attribute. The default framestyle is `:axes`.
PlotExample("Lines and markers with varying colors",
"""
You can use the `line_z` and `marker_z` properties to associate a color with
each line segment or marker in the plot.
each line segment or marker in the plot.
""",
[:(begin
t = linspace(0, 1, 100)
t = range(0, stop=1, length=100)
θ = 6π .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
@@ -439,7 +439,7 @@ each line segment or marker in the plot.
# make and display one plot
function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
Plots._debugMode.on = debug
info("Testing plot: $pkgname:$idx:$(_examples[idx].header)")
@info("Testing plot: $pkgname:$idx:$(_examples[idx].header)")
backend(pkgname)
backend()
map(eval, _examples[idx].exprs)
+6 -6
View File
@@ -268,7 +268,7 @@ function GridLayout(dims...;
widths = zeros(dims[2]),
heights = zeros(dims[1]),
kw...)
grid = Matrix{AbstractLayout}(dims...)
grid = Matrix{AbstractLayout}(undef, dims...)
layout = GridLayout(
parent,
(20mm, 5mm, 2mm, 10mm),
@@ -357,10 +357,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
# get the max horizontal (left and right) padding over columns,
# and max vertical (bottom and top) padding over rows
# TODO: add extra padding here
pad_left = maximum(minpad_left, 1)
pad_top = maximum(minpad_top, 2)
pad_right = maximum(minpad_right, 1)
pad_bottom = maximum(minpad_bottom, 2)
pad_left = maximum(minpad_left, dims = 1)
pad_top = maximum(minpad_top, dims = 2)
pad_right = maximum(minpad_right, dims = 1)
pad_bottom = maximum(minpad_bottom, dims = 2)
# make sure the perimeter match the parent
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
@@ -566,7 +566,7 @@ function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
for r=1:nr, c=1:nc
l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
plt = shift!(plts) # grab the first plot out of the list
plt = popfirst!(plts) # grab the first plot out of the list
layout[r,c] = plt.layout
append!(subplots, plt.subplots)
merge!(spmap, plt.spmap)
+33 -34
View File
@@ -146,7 +146,8 @@ function Base.display(::PlotsDisplay, plt::Plot)
end
# override the REPL display to open a gui window
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
using REPL
Base.display(::REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
_do_plot_show(plt, showval::Bool) = showval && gui(plt)
@@ -157,17 +158,6 @@ end
# ---------------------------------------------------------
const _mimeformats = Dict(
"application/eps" => "eps",
"image/eps" => "eps",
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
"image/svg+xml" => "svg",
"text/plain" => "txt",
"application/x-tex" => "tex",
)
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
@@ -177,7 +167,7 @@ const _best_html_output_type = KW(
)
# a backup for html... passes to svg or png depending on the html_output_format arg
function Base.show(io::IO, ::MIME"text/html", plt::Plot)
function _show(io::IO, ::MIME"text/html", plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
@@ -191,26 +181,32 @@ function Base.show(io::IO, ::MIME"text/html", plt::Plot)
elseif output_type == :txt
show(io, MIME("text/plain"), plt)
else
error("only png or svg allowed. got: $output_type")
error("only png or svg allowed. got: $(repr(output_type))")
end
end
function _show(io::IO, m, plt::Plot{B}) where B
# Base.show_backtrace(STDOUT, backtrace())
warn("_show is not defined for this backend. m=", string(m))
# delegate mimewritable (showable on julia 0.7) to _show instead
function Base.mimewritable(m::M, plt::P) where {M<:MIME, P<:Plot}
return hasmethod(_show, Tuple{IO, M, P})
end
function _display(plt::Plot)
warn("_display is not defined for this backend.")
@warn("_display is not defined for this backend.")
end
# for writing to io streams... first prepare, then callback
for mime in keys(_mimeformats)
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B}) where B
for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml",
"application/eps", "application/pdf", "application/postscript",
"application/x-tex")
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
prepare_output(plt)
_show(io, m, plt)
end
end
# default text/plain for all backends
_show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
@@ -218,9 +214,10 @@ closeall() = closeall(backend())
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
if is_installed("FileIO")
@eval import FileIO
function _show(io::IO, ::MIME"image/png", plt::Plot)
function _show(io::IO, ::MIME"image/png", plt::Plot{<:PDFBackends})
fn = tempname()
# first save a pdf file
@@ -234,7 +231,7 @@ if is_installed("FileIO")
FileIO.save(pngfn, s)
# now write from the file
write(io, readstring(open(pngfn)))
write(io, read(open(pngfn), String))
end
end
@@ -258,7 +255,7 @@ end
# IJulia
# ---------------------------------------------------------
@require IJulia begin
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
if IJulia.inited
"""
@@ -288,7 +285,10 @@ end
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :png
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
@@ -304,11 +304,6 @@ end
out
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
ENV["MPLBACKEND"] = "Agg"
end
end
@@ -316,15 +311,12 @@ end
# ---------------------------------------------------------
# Atom PlotPane
# ---------------------------------------------------------
@require Juno begin
@require Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" begin
import Hiccup, Media
if Juno.isactive()
Media.media(Plot, Media.Plot)
_show(io::IO, m::MIME"text/plain", plt::Plot{B}) where {B} = print(io, "Plot{$B}()")
function Juno.render(e::Juno.Editor, plt::Plot)
Juno.render(e, nothing)
end
@@ -333,13 +325,20 @@ end
function Juno.render(pane::Juno.PlotPane, plt::Plot)
# temporarily overwrite size to be Atom.plotsize
sz = plt[:size]
dpi = plt[:dpi]
thickness_scaling = plt[:thickness_scaling]
jsize = Juno.plotsize()
jsize[1] == 0 && (jsize[1] = 400)
jsize[2] == 0 && (jsize[2] = 500)
plt[:size] = jsize
scale = minimum(jsize[i] / sz[i] for i in 1:2)
plt[:size] = (s * scale for s in sz)
plt[:dpi] = Plots.DPI
plt[:thickness_scaling] *= scale
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end
# special handling for PlotlyJS
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
+10 -7
View File
@@ -11,11 +11,13 @@ function _expand_seriestype_array(d::KW, args)
sts = get(d, :seriestype, :path)
if typeof(sts) <: AbstractArray
delete!(d, :seriestype)
RecipeData[begin
rd = Vector{RecipeData}(undef, size(sts, 1))
for r in 1:size(sts, 1)
dc = copy(d)
dc[:seriestype] = sts[r:r,:]
RecipeData(dc, args)
end for r=1:size(sts,1)]
rd[r] = RecipeData(dc, args)
end
rd
else
RecipeData[RecipeData(copy(d), args)]
end
@@ -70,7 +72,7 @@ function _process_userrecipes(plt::Plot, d::KW, args)
# grab the first in line to be processed and either add it to the kw_list or
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
# for further processing.
next_series = shift!(still_to_process)
next_series = popfirst!(still_to_process)
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(next_series) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
@@ -151,7 +153,7 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
x, y = kw[:x], kw[:y]
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
sx = [ignorenan_minimum(x), ignorenan_maximum(x)]
sy = β * sx + α
sy = β .* sx .+ α
push!(kw_list, merge(copy(kw), KW(
:seriestype => :path,
:x => sx,
@@ -327,9 +329,9 @@ end
function _override_seriestype_check(d::KW, st::Symbol)
# do we want to override the series type?
if !is3d(st)
if !is3d(st) && !(st in (:contour,:contour3d))
z = d[:z]
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
if !isa(z, Nothing) && (size(d[:x]) == size(d[:y]) == size(z))
st = (st == :scatter ? :scatter3d : :path3d)
d[:seriestype] = st
end
@@ -398,6 +400,7 @@ function _process_seriesrecipe(plt::Plot, d::KW)
sp = _prepare_subplot(plt, d)
_prepare_annotations(sp, d)
_expand_subplot_extrema(sp, d, st)
_update_series_attributes!(d, plt, sp)
_add_the_series(plt, sp, d)
else
+9 -10
View File
@@ -1,10 +1,10 @@
mutable struct CurrentPlot
nullableplot::Nullable{AbstractPlot}
nullableplot::Union{AbstractPlot, Nothing}
end
const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
const CURRENT_PLOT = CurrentPlot(nothing)
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
isplotnull() = CURRENT_PLOT.nullableplot == nothing
"""
current()
@@ -14,9 +14,9 @@ function current()
if isplotnull()
error("No current plot/subplot")
end
get(CURRENT_PLOT.nullableplot)
CURRENT_PLOT.nullableplot
end
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = Nullable(plot))
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
# ---------------------------------------------------------
@@ -46,9 +46,8 @@ When you pass in matrices, it splits by columns. To see the list of available at
function, where `attr` is the symbol `:Series:`, `:Subplot:`, `:Plot` or `:Axis`. Pass any attribute to `plotattr`
as a String to look up its docstring; e.g. `plotattr("seriestype")`.
"""
# this creates a new plot with args/kw and sets it to be the current plot
function plot(args...; kw...)
# this creates a new plot with args/kw and sets it to be the current plot
d = KW(kw)
preprocessArgs!(d)
@@ -66,7 +65,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}(undef, n)
plts[1] = plt1
for (i,plt) in enumerate(plts_tail)
plts[i+1] = plt
@@ -169,7 +168,7 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
if !isempty(args) && !isdefined(Main, :StatPlots) &&
first(split(string(typeof(args[1])), ".")) == "DataFrames"
warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
@warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
end
# --------------------------------
@@ -193,7 +192,7 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
still_to_process = kw_list
kw_list = KW[]
while !isempty(still_to_process)
next_kw = shift!(still_to_process)
next_kw = popfirst!(still_to_process)
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
end
+7 -6
View File
@@ -80,7 +80,7 @@ end
@recipe function f(::Type{Val{:hline}}, x, y, z)
n = length(y)
newx = repmat(Float64[-1, 1, NaN], n)
newx = repeat(Float64[-1, 1, NaN], n)
newy = vec(Float64[yi for i=1:3,yi=y])
x := newx
y := newy
@@ -92,7 +92,7 @@ end
@recipe function f(::Type{Val{:vline}}, x, y, z)
n = length(y)
newx = vec(Float64[yi for i=1:3,yi=y])
newy = repmat(Float64[-1, 1, NaN], n)
newy = repeat(Float64[-1, 1, NaN], n)
x := newx
y := newy
seriestype := :straightline
@@ -413,6 +413,7 @@ end
z := nothing
seriestype := :shape
label := ""
widen --> false
()
end
@deps plots_heatmap shape
@@ -585,7 +586,7 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
n_samples = length(linearindices(first(vs)))
n_samples = length(LinearIndices(first(vs)))
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
nd = n_samples^(1/(2+N))
@@ -619,10 +620,10 @@ _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...))
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
map(dim -> _hist_edge(vs, dim, binning), (1:N...))
map(dim -> _hist_edge(vs, dim, binning), (1:N...,))
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
@@ -791,7 +792,7 @@ 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)}(undef, 0), Array{Float64}(undef, 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)
+10 -10
View File
@@ -14,7 +14,7 @@ all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surfac
convertToAnyVector(x, d::KW) = error("No user recipe defined for $(typeof(x))")
# missing
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
convertToAnyVector(v::Nothing, d::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
@@ -46,7 +46,7 @@ convertToAnyVector(v::Volume, d::KW) = Any[v], nothing
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# # dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
@@ -72,19 +72,19 @@ end
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1)
compute_x(x::Nothing, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z::Nothing) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
@@ -99,9 +99,9 @@ nobigs(v) = v
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
compute_xyz(x::Nothing, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
@@ -627,7 +627,7 @@ group_as_matrix(t) = false
else
g = args[1]
if length(g.args) == 1
x = zeros(Int64, lengthGroup)
x = zeros(Int, lengthGroup)
for indexes in groupby.groupIds
x[indexes] = 1:length(indexes)
end
+1 -1
View File
@@ -93,7 +93,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
cfunc(RGB(def))
elseif eltype(def) <: Colorant
cfunc.(RGB.(def))
elseif contains(string(arg), "color")
elseif occursin("color", string(arg))
cfunc.(RGB.(plot_color.(def)))
else
def
+1 -1
View File
@@ -6,7 +6,7 @@ const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
struct PlotsDisplay <: Display end
struct PlotsDisplay <: AbstractDisplay end
# -----------------------------------------------------------
+61 -28
View File
@@ -4,7 +4,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)
edges = collect(linspace(lo, hi, nbins+1))
edges = collect(range(lo, stop=hi, length=nbins+1))
midpoints = calcMidpoints(edges)
buckets = Int[max(2, min(searchsortedfirst(edges, x), length(edges)))-1 for x in data]
counts = zeros(Int, length(midpoints))
@@ -119,7 +119,7 @@ function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
n, m = size(z)
# idx = 0
colors = ColorGradient(vec(z))
newz = reshape(linspace(0, 1, n*m), n, m)
newz = reshape(range(0, stop=1, length=n*m), n, m)
newz, colors
# newz = zeros(n, m)
# for i=1:n, j=1:m
@@ -195,9 +195,13 @@ end
function iter_segments(series::Series)
x, y, z = series[:x], series[:y], series[:z]
if has_attribute_segments(series)
return [i:(i + 1) for i in 1:(length(y) - 1)]
if series[:seriestype] in (:scatter, :scatter3d)
return [[i] for i in 1:length(y)]
else
return [i:(i + 1) for i in 1:(length(y) - 1)]
end
else
segs = UnitRange{Int64}[]
segs = UnitRange{Int}[]
args = is3d(series) ? (x, y, z) : (x, y)
for seg in iter_segments(args...)
push!(segs, seg)
@@ -207,7 +211,7 @@ function iter_segments(series::Series)
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 -> try isnan(_cycle(a,i)) catch MethodError false end, 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)
@@ -255,7 +259,7 @@ float_extended_type(x::AbstractArray{T}) where {T<:Real} = Float64
nop() = nothing
notimpl() = error("This has not been implemented yet")
isnothing(x::Void) = true
isnothing(x::Nothing) = true
isnothing(x) = false
_cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
@@ -303,6 +307,7 @@ function _expand_limits(lims, x)
lims[2] = NaNMath.max(lims[2], e2)
# catch err
# warn(err)
catch
end
nothing
end
@@ -339,7 +344,7 @@ function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
end
end
createSegments(z) = collect(repmat(reshape(z,1,:),2,1))[2:end]
createSegments(z) = collect(repeat(reshape(z,1,:),2,1))[2:end]
Base.first(c::Colorant) = c
Base.first(x::Symbol) = x
@@ -351,22 +356,21 @@ sortedkeys(d::Dict) = sort(collect(keys(d)))
const _scale_base = Dict{Symbol, Real}(
:log10 => 10,
:log2 => 2,
:ln => e,
:ln => ,
)
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec, scale::Symbol = :identity)
function _heatmap_edges(v::AVec)
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
extra_min = (v[2] - v[1]) / 2
extra_max = (v[end] - v[end - 1]) / 2
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
end
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec, scale::Symbol = :identity)
f, invf = scalefunc(scale), invscalefunc(scale)
map(invf, _heatmap_edges(map(f,v)))
end
function calc_r_extrema(x, y)
xmin, xmax = ignorenan_extrema(x)
@@ -378,7 +382,7 @@ end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
theta, r = filter_radial_data(x, y, r_extrema)
r = (r - rmin) / (rmax - rmin)
r = (r .- rmin) ./ (rmax .- rmin)
x = r.*cos.(theta)
y = r.*sin.(theta)
x, y
@@ -447,8 +451,8 @@ limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
Base.convert(::Type{Vector{T}}, rng::Range{T}) where {T<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::Range{S}) where {T<:Real,S<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::AbstractRange{T}) where {T<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::AbstractRange{S}) where {T<:Real,S<:Real} = T[x for x in rng]
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
@@ -620,7 +624,7 @@ function get_linecolor(series, i::Int = 1)
lc = series[:linecolor]
lz = series[:line_z]
if lz == nothing
isa(lc, ColorGradient) ? lc : _cycle(lc, i)
isa(lc, ColorGradient) ? lc : plot_color(_cycle(lc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(lc, ColorGradient) ? lc : cgrad()
@@ -644,7 +648,7 @@ function get_fillcolor(series, i::Int = 1)
fc = series[:fillcolor]
fz = series[:fill_z]
if fz == nothing
isa(fc, ColorGradient) ? fc : _cycle(fc, i)
isa(fc, ColorGradient) ? fc : plot_color(_cycle(fc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(fc, ColorGradient) ? fc : cgrad()
@@ -656,6 +660,31 @@ function get_fillalpha(series, i::Int = 1)
_cycle(series[:fillalpha], i)
end
function get_markercolor(series, i::Int = 1)
mc = series[:markercolor]
mz = series[:marker_z]
if mz == nothing
isa(mc, ColorGradient) ? mc : plot_color(_cycle(mc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(mc, ColorGradient) ? mc : cgrad()
grad[clamp((_cycle(mz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
function get_markeralpha(series, i::Int = 1)
_cycle(series[:markeralpha], i)
end
function get_markerstrokecolor(series, i::Int = 1)
msc = series[:markerstrokecolor]
isa(msc, ColorGradient) ? msc : _cycle(msc, i)
end
function get_markerstrokealpha(series, i::Int = 1)
_cycle(series[:markerstrokealpha], i)
end
function has_attribute_segments(series::Series)
# we want to check if a series needs to be split into segments just because
# of its attributes
@@ -666,7 +695,7 @@ function has_attribute_segments(series::Series)
end
series[:seriestype] == :shape && return false
# ... else we check relevant attributes if they have multiple inputs
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z))
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z, :marker_z))
end
# ---------------------------------------------------------------
@@ -818,8 +847,8 @@ end
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))
extendSeriesData(v::Range{T}, z::Real) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::Range{T}, z::AVec) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AbstractRange{T}, z::Real) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AbstractRange{T}, z::AVec) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AVec{T}, z::Real) where {T} = (push!(v, convert(T, z)); v)
extendSeriesData(v::AVec{T}, z::AVec) where {T} = (append!(v, convert(Vector{T}, z)); v)
@@ -828,7 +857,7 @@ extendSeriesData(v::AVec{T}, z::AVec) where {T} = (append!(v, convert(Ve
# NOTE: backends should implement the following methods to get/set the x/y/z data objects
tovec(v::AbstractVector) = v
tovec(v::Void) = zeros(0)
tovec(v::Nothing) = zeros(0)
function getxy(plt::Plot, i::Integer)
d = plt.series_list[i].d
@@ -1110,9 +1139,9 @@ function convert_sci_unicode(label::AbstractString)
"×10" => "×10^{",
)
for key in keys(unicode_dict)
label = replace(label, key, unicode_dict[key])
label = replace(label, key => unicode_dict[key])
end
if contains(label, "10^{")
if occursin("10^{", label)
label = string(label, "}")
end
label
@@ -1188,3 +1217,7 @@ function shape_data(series)
end
return x, y
end
function construct_categorical_data(x::AbstractArray, axis::Axis)
map(xi -> axis[:discrete_values][searchsortedfirst(axis[:continuous_values], xi)], x)
end
+9 -9
View File
@@ -2,20 +2,20 @@
using VisualRegressionTests
# using ExamplePlots
import DataFrames, RDatasets
# import DataFrames, RDatasets
# don't let pyplot use a gui... it'll crash
# note: Agg will set gui -> :none in PyPlot
ENV["MPLBACKEND"] = "Agg"
try
@eval import PyPlot
info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
end
# ENV["MPLBACKEND"] = "Agg"
# try
# @eval import PyPlot
# info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
# end
using Plots
using StatPlots
using Base.Test
# using StatPlots
using Test
default(size=(500,300))
@@ -23,7 +23,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.17.0"
const _current_plots_version = v"0.17.3"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
+3 -3
View File
@@ -13,7 +13,7 @@ img_eps = isinteractive() ? 1e-2 : 10e-2
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
image_comparison_facts(:gr, eps=img_eps)
image_comparison_facts(:gr, eps=img_eps, skip = [25, 30])
end
@@ -39,7 +39,7 @@ end
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# if is_linux() && isinteractive()
# if Sys.islinux() && isinteractive()
# image_comparison_facts(:plotlyjs,
# skip=[
# 2, # animation (skipped for speed)
@@ -79,7 +79,7 @@ end
# @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)
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
# end
+8 -5
View File
@@ -1,15 +1,18 @@
using Pkg
Pkg.add("ImageMagick")
Pkg.build("ImageMagick")
# Pkg.clone("GR")
# Pkg.build("GR")
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
Pkg.checkout("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
# Pkg.clone("https://github.com/JuliaStats/KernelDensity.jl.git")
Pkg.clone("StatPlots")
# Pkg.add("StatPlots")
Pkg.checkout("PlotUtils")
Pkg.checkout("RecipesBase")
# Pkg.clone("Blink")
# Pkg.build("Blink")
@@ -22,9 +25,9 @@ Pkg.checkout("PlotUtils")
# Pkg.clone("VisualRegressionTests")
# need this to use Conda
ENV["PYTHON"] = ""
Pkg.add("PyPlot")
Pkg.build("PyPlot")
# ENV["PYTHON"] = ""
# Pkg.add("PyPlot")
# Pkg.build("PyPlot")
# Pkg.add("InspectDR")