Compare commits

...

896 Commits

Author SHA1 Message Date
Michael Krabbe Borregaard 2d217edc15 update news.md 2018-08-14 23:56:21 +02:00
Michael Krabbe Borregaard b55d13bc21 Merge pull request #1655 from roshanshariff/julia-1.0
Fix julia 0.7 deprecated syntax in Plotly backend.
2018-08-14 23:53:35 +02:00
Michael Krabbe Borregaard 1f9468e029 Merge pull request #1656 from mkborregaard/pyplot
Add more packages to PyPlot string
2018-08-14 23:53:03 +02:00
Roshan Shariff 593804096d Fix julia 0.7 deprecated syntax in Plotly backend. 2018-08-14 15:38:55 -06:00
Michael Krabbe Borregaard befb14682d Add more packages to PyPlot string 2018-08-14 23:28:18 +02:00
Michael Krabbe Borregaard 07a6700ab6 Merge pull request #1654 from ma-laforge/hdf5
Deal w/deprecation of Nullable.
2018-08-14 22:57:17 +02:00
MA Laforge 8131953e49 Deal w/deprecation of Nullable.
Also use new LinearIndices API.
2018-08-14 13:04:22 -07:00
Michael Krabbe Borregaard 7e360aa915 Merge pull request #1651 from mkborregaard/master
Update instances of `findfirst` to 1.0 syntax
2018-08-14 10:24:40 +02:00
Michael Krabbe Borregaard 0710fba638 Update instances of findfirst to 1.0 syntax 2018-08-14 10:24:10 +02:00
Michael Krabbe Borregaard afb7a17e5f Merge pull request #1650 from mkborregaard/master
1.0 updates to animations
2018-08-14 09:20:34 +02:00
Michael Krabbe Borregaard badf302756 Explicitly specify assignment to global 2018-08-14 09:19:32 +02:00
Michael Krabbe Borregaard 99941dde8f info --> @info 2018-08-14 09:13:27 +02:00
Michael Krabbe Borregaard e5c55b6962 Merge pull request #1647 from joshday/patch-1
import findnz from SparseArrays
2018-08-13 15:05:42 +02:00
Josh Day 7a7f4cb306 import findnz from SparseArrays 2018-08-13 08:58:38 -04:00
Michael Krabbe Borregaard d084e31065 Merge pull request #1644 from mkborregaard/master
Don't broadcast `plot_color`; fix #1641
2018-08-13 10:08:57 +02:00
Michael Krabbe Borregaard 12008ef1c6 Don't broadcast plot_color; fix #1641
On 1.0 you can no longer pass a singleton argument to broadcast without escaping with `Ref`. But - `plot_color` has `Vector` methods, so it should be fine to not broadcast here. The example from the PR that introduced the broadcast here still works on this PR https://github.com/JuliaPlots/Plots.jl/pull/1467#issue-178940271
2018-08-13 10:07:03 +02:00
Michael Krabbe Borregaard 6dc0823b73 Merge pull request #1637 from mkborregaard/master
update news.md
2018-08-11 18:26:18 +01:00
Michael Krabbe Borregaard 0f9220c965 update news.md 2018-08-11 18:25:49 +01:00
Michael Krabbe Borregaard 5c21261aea Merge pull request #1636 from oschulz/fixes-julia-v1.0
More fixes for Julia v1.0
2018-08-11 13:51:28 +01:00
Oliver Schulz 1fda0df03e Fix _stepbins_path (new Julia v0.7/v1.0 iteration API) 2018-08-11 13:41:33 +01:00
Oliver Schulz d4406bb806 Use length(eachindex(...)) instead of length(linearindices(...)) 2018-08-11 13:21:06 +01:00
Michael Krabbe Borregaard b1095e29bc Merge pull request #1635 from mkborregaard/master
Final 1.0 fixes
2018-08-11 11:25:54 +01:00
Michael Krabbe Borregaard 3e56aa43e4 linspace -> range 2018-08-11 11:24:54 +01:00
Michael Krabbe Borregaard c2dc030fae fieldnames(x) -> fieldnames(typeof(x)) 2018-08-11 11:24:45 +01:00
Michael Krabbe Borregaard 340cd0a1fe Merge pull request #1634 from mkborregaard/master
replace warn -> @warn
2018-08-10 18:16:37 +01:00
Michael Krabbe Borregaard 2844e706a9 warn -> @warn 2018-08-10 18:14:14 +01:00
Michael Krabbe Borregaard 55ee64b4e6 Merge pull request #1630 from mkborregaard/fix1.0
1.0 fixes WIP RFC
2018-08-10 11:02:58 +01:00
Michael Krabbe Borregaard 3849700a28 readstring -> read 2018-08-09 17:03:44 +01:00
Michael Krabbe Borregaard 3dd0049973 No longer overload broadcast 2018-08-09 17:00:17 +01:00
Michael Krabbe Borregaard 8e6ccf1b20 typo fix 2018-08-09 16:55:30 +01:00
Michael Krabbe Borregaard c544dbbbb7 rename mimewritable 2018-08-09 16:53:37 +01:00
Michael Krabbe Borregaard 5205ac38ad Implement new iterator protocol 2018-08-09 16:53:27 +01:00
Michael Krabbe Borregaard 0143807515 Remove deprecated endof 2018-08-09 16:52:43 +01:00
Michael Krabbe Borregaard 5176ab1382 Merge pull request #1625 from mkborregaard/master
No longer include files for Revise
2018-08-09 16:31:56 +01:00
Daniel Schwabeneder b0d54f7c5d Merge pull request #1623 from JuliaPlots/fbot/deps
Fix deprecations
2018-08-09 14:16:47 +02:00
Michael Krabbe Borregaard 96f0335af4 No longer include files for Revise
This is no longer necessary in 0.7
2018-08-09 12:46:09 +01:00
Michael Krabbe Borregaard 572f8ebfde Merge pull request #1624 from mkborregaard/master
Remove Dates from Require again
2018-08-09 12:42:33 +01:00
Michael Krabbe Borregaard 07a8d844d2 Remove dates again 2018-08-09 12:41:56 +01:00
Michael Krabbe Borregaard c48abef5f8 Merge pull request #1622 from mkborregaard/master
Change dep to julia 0.7 and add Dates to Require
2018-08-09 09:28:23 +01:00
Michael Krabbe Borregaard 9b3679792d change dep to 0.7 and add Dates to require 2018-08-09 09:26:36 +01:00
Michael Krabbe Borregaard cb00983db3 Allow bin to be a heterogeneous Tuple
fix #https://github.com/JuliaPlots/StatPlots.jl/issues/156
2018-08-09 09:13:34 +01:00
femtocleaner[bot] 83686866cc Fix deprecations 2018-08-08 12:42:18 +00:00
Daniel Schwabeneder 7a49249384 Merge pull request #1619 from daschw/init
fix merge conflicts
2018-08-08 10:34:40 +03:00
Daniel Schwabeneder 0548793bfd remove Juno requires code 2018-08-08 09:28:30 +02:00
Daniel Schwabeneder cd770f70c0 fix merge conflict relicts 2018-08-08 09:24:37 +02:00
Daniel Schwabeneder a3f1950a18 Merge pull request #1616 from apalugniok/ticks
Make xticks!/yticks! behave like plot(xticks!/yticks! = ). (Fixes #1605)
2018-08-07 07:15:16 -08:00
Daniel Schwabeneder 1874c28cad Merge pull request #1601 from daschw/requires
RFC: use Requires.jl for backend dependencies
2018-08-07 07:14:21 -08:00
Daniel Schwabeneder 317f01a6b4 fix init.jl 2018-08-06 18:02:19 +02:00
Daniel Schwabeneder 5e8eff074d require PyCall 2018-08-06 17:55:02 +02:00
Andrew Palugniok db028f2774 Make xticks!/yticks! behave like plot(xticks!/yticks! = ) 2018-08-05 14:29:00 +01:00
Daniel Schwabeneder a82a154be9 remove old juno inti code 2018-08-04 06:45:18 +02:00
Daniel Schwabeneder af01927807 add init.jl 2018-08-04 06:44:12 +02:00
Daniel Schwabeneder f60aac93ab use Requires.jl for backend dependencies 2018-08-04 06:44:12 +02:00
Daniel Schwabeneder 4860bf3f19 Merge pull request #1615 from pfitzseb/sp/junodisplay
Fix display on Juno 0.7
2018-08-04 06:05:00 +02:00
Sebastian Pfitzner adf2af82b4 fix display on Juno 0.7 2018-08-03 12:37:12 +02:00
Josef Heinen 8d16563014 Update gr.jl 2018-08-01 13:12:48 +02:00
Daniel Schwabeneder da765a5eec Merge pull request #1610 from daschw/pyplot-thickness
fix pyplot thickness_scaling (fix #1606)
2018-07-28 08:53:03 +02:00
Daniel Schwabeneder 72c4962e97 prepare backports release 2018-07-26 16:43:05 +02:00
Daniel Schwabeneder 789cf1d66b fix legend frame 2018-07-25 23:39:55 +02:00
Daniel Schwabeneder 64ec922d7f fix thickness_scaling in pyplot 2018-07-25 23:32:02 +02:00
Daniel Schwabeneder 85b3aefd67 add init.jl 2018-07-20 17:15:43 +02:00
Daniel Schwabeneder af0dabec99 use Requires.jl for backend dependencies 2018-07-19 22:33:36 +02:00
Daniel Schwabeneder de85983247 Merge pull request #1596 from wfrgra/minorgrid
Minorgrid and minor ticks
2018-07-17 17:54:38 +02:00
Will Grant 7eaae3a6d5 Add full keyword control of minor grid 2018-07-16 17:37:19 +10:00
Will Grant 403b57c076 extend ticks beyond major grid, to axis limits 2018-07-11 17:59:47 +10:00
Will Grant dd434b89d2 add minor grid and tick marks. Works, but doesn't extend beyond major ticks 2018-07-11 17:17:45 +10:00
Daniel Schwabeneder 1a3d58e09b Merge pull request #1594 from fredrikekre/fe/0.72
additional fixes
2018-07-05 09:01:26 +02:00
Fredrik Ekre 89ae239743 adjust CI scripts 2018-07-05 08:46:17 +02:00
Fredrik Ekre c785d1509b additional fixes 2018-07-05 08:33:14 +02:00
Daniel Schwabeneder 9e412555bb Merge pull request #1585 from JuliaPlots/julia0.7
Switch to 0.7 on master
2018-07-05 08:14:03 +02:00
Daniel Schwabeneder 0717805773 more deprecation fixes 2018-07-04 22:33:51 +02:00
Daniel Schwabeneder d045c5a390 Merge pull request #1592 from JuliaPlots/revert-1591-fbot/deps
Revert "Fix deprecations"
2018-07-04 21:10:31 +02:00
Daniel Schwabeneder 3cc0d0c735 Revert "Fix deprecations" 2018-07-04 21:10:08 +02:00
Daniel Schwabeneder 9a3c727532 Merge pull request #1591 from JuliaPlots/fbot/deps
Fix deprecations
2018-07-04 21:08:10 +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] 3a769549d8 Fix deprecations 2018-07-02 20:33:16 +00: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
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
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
Daniel Schwabeneder fde0fa673b Merge pull request #1482 from daschw/release
prepare release
2018-04-13 17:09:12 +02:00
Daniel Schwabeneder c93d5e7830 Merge pull request #1481 from daschw/gr-mindep
add minimal version for GR dependency
2018-04-13 16:43:01 +02:00
Daniel Schwabeneder e305b973b2 Merge pull request #1477 from daschw/heatmap-recipe
RFC: WIP: Heatmap recipe
2018-04-13 16:42:31 +02:00
Daniel Schwabeneder 506d3611fd prepare release 2018-04-13 16:33:38 +02:00
Daniel Schwabeneder 14b644777d add minimal version for GR dependency 2018-04-13 16:21:18 +02:00
Daniel Schwabeneder b9c23c75f4 Merge pull request #1380 from davidanthoff/always-install-gr
Add GR to REQUIRE
2018-04-13 16:18:37 +02:00
Daniel Schwabeneder af60d03060 make alternative plots_heatmap seriestype 2018-04-13 16:14:03 +02:00
Andrew Palugniok adb66cae9d Merge pull request #1479 from apalugniok/pgfplots-scientific
Replace `×` with `\times` for PGFPlots. (Fixes #1464)
2018-04-10 09:20:29 +01: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
Andrew Palugniok 8abd70bed8 Replace × with \times for PGFPlots. 2018-04-09 09:46:01 +01:00
Daniel Schwabeneder 91cd6c1954 Merge pull request #1443 from fedxa/fedxa-autosciaxis
Partial attempt to fix labeling to atomatically scientific notation
2018-04-09 10:40:26 +02:00
Daniel Schwabeneder 7a702489d0 fixes for plotly 2018-04-07 15:54:06 +02:00
Daniel Schwabeneder d33331f650 Merge pull request #1476 from daschw/default-theme
allow to set the theme in PLOTS_DEFAULTS
2018-04-07 15:34:05 +02:00
Daniel Schwabeneder 8e3bd07c91 set line_z 2018-04-07 14:37:15 +02:00
Daniel Schwabeneder ad55551819 allow to set the theme in PLOTS_DEFAULTS 2018-04-07 08:55:52 +02:00
Daniel Schwabeneder 1d38e50281 Merge pull request #1475 from daschw/pgf-legendmarker
Filled legend marker for filled areas in PGFPlots
2018-04-06 20:20:09 +02:00
Daniel Schwabeneder cef0882e80 Merge pull request #1471 from hycakir/master
Remove SVG support for plotly, which is not there
2018-04-06 18:50:36 +02:00
Daniel Schwabeneder 5a07c4917e fix multiple series 2018-04-06 18:37:57 +02:00
Daniel Schwabeneder e498d091cd filled legend marker for filled area in PGFPlots 2018-04-06 17:14:19 +02:00
Michael Krabbe Borregaard 8ba30c5453 Merge pull request #1474 from mkborregaard/master
Improve histogram2d bin estimation
2018-04-06 11:45:23 +02:00
Daniel Schwabeneder 685e2eaff7 implement heatmapr recipe 2018-04-06 10:32:45 +02:00
Michael K. Borregaard 6ca8471c64 Improve histogram2d bin estimation
The existing one would error when the correlation was high
2018-04-06 09:09:03 +02:00
Hamza Yusuf Çakır e30f4652af Remove SVG support, which is not there
plotly backend does not support SVG output. What it shows is the HTML output of Plotly backend.
This commit makes the request for SVG output to return an error as in PNG.
2018-04-05 02:53:50 +03:00
Daniel Schwabeneder 9acb89ba8a Merge pull request #1467 from daschw/segments
Segments: vector arguments, line_z and fill_z for GR, PyPlot, Plotly(JS) and PGFPlots
2018-04-04 23:27:48 +02:00
Daniel Schwabeneder 9b9a775a41 fix test errors 2018-04-03 18:43:18 +02:00
Daniel Schwabeneder a6f11cdb31 fix pyplot (leave commented lines for possible future work) 2018-04-02 23:21:57 +02:00
Daniel Schwabeneder 777642ef55 pyplot use linecollection only WITHOUT fillrange 2018-04-02 22:44:29 +02:00
Daniel Schwabeneder d1d7fd258f add fill_z and line_z to supported pgfplots attr 2018-04-02 22:14:50 +02:00
Daniel Schwabeneder 7e4635de26 fix transparency on GR 2018-04-02 22:11:22 +02:00
Daniel Schwabeneder d7b2173066 fix linestyle in pyplot 2018-04-02 22:08:00 +02:00
Daniel Schwabeneder 55e9c8c9eb implement fillrange, vector arguments, line_z and fill_z for pgfplots 2018-04-02 21:39:45 +02:00
Daniel Schwabeneder c34e1d3c19 implement vector arguments, line_z and fill_z for plotly 2018-04-02 18:35:26 +02:00
Daniel Schwabeneder f89b1ba303 implement vector arguments for GR and PyPlot 2018-04-02 00:41:13 +02:00
Daniel Schwabeneder fc7b6dd0c6 some bug fixes 2018-03-31 18:41:43 +02:00
Daniel Schwabeneder 1b5240a513 introduce iter_segments(series::Series) considering certain vector series attributes 2018-03-31 18:18:58 +02:00
Christopher Rackauckas 4bcf43c84b Update imgcomp.jl 2018-03-31 09:11:02 -07:00
Daniel Schwabeneder b57abfd563 remove sp arg from get_linecolor and get_fillcolor 2018-03-31 14:45:12 +02:00
Daniel Schwabeneder bfc26fa407 Merge pull request #1445 from daschw/infinite-objects
Infinite objects (fix #1422)
2018-03-28 21:49:32 +02:00
Daniel Schwabeneder e7b435b47f Merge pull request #1454 from CarloLucibello/master
import filter from Base
2018-03-28 21:48:51 +02:00
CarloLucibello dd6842522f avoid import 2018-03-28 09:50:46 -07:00
Daniel Schwabeneder f56d944870 hspan and vspan recipes 2018-03-28 11:32:23 +02:00
Daniel Schwabeneder 772b79306d Merge pull request #1460 from daschw/pyplot-marker_z
PyPlot: fix markercolor in legend for marker_z with st = :path
2018-03-28 10:53:23 +02:00
Daniel Schwabeneder 4ef2c6286b Merge pull request #1459 from daschw/mplot3d
import mplot3d in pyplot (fix #1457)
2018-03-27 15:45:02 +02:00
Daniel Schwabeneder a5f7c1b867 fix markercolor in legend for marker_z with st = :path 2018-03-27 14:24:26 +02:00
Daniel Schwabeneder 4d8ef2a008 import mplot3d in pyplot 2018-03-27 13:41:18 +02:00
CarloLucibello 8bc28d472f import filter 2018-03-24 19:12:18 -04:00
piever 3753ab1b55 increase version number for tests 2018-03-22 20:37:27 +00:00
Pietro Vertechi babc600915 Merge pull request #1450 from JuliaPlots/pv/release
update news
2018-03-22 14:22:03 -06:00
piever b2f92e246e update news 2018-03-22 19:39:18 +00:00
Fedor Bezrukov 92f9ccce5c Added :plain formatter 2018-03-21 23:58:26 +00:00
Daniel Schwabeneder 0ace28b784 extend straightline data beyond axes limits 2018-03-21 11:42:01 +01:00
Fedor Bezrukov bd06f0c713 Fixed broken behaviour for function :formatter, and pgfplots 2018-03-21 10:07:09 +00:00
Fedor Bezrukov 4e5c88eb74 Fixed unicode display for plotly() 2018-03-21 00:12:57 +00:00
Daniel Schwabeneder 004ad15875 Merge pull request #1437 from daschw/plotly-bar
RFC: use bar recipe in plotly
2018-03-20 17:11:37 +01:00
Daniel Schwabeneder 1c0a731ff6 fix typo in glvisualize 2018-03-19 21:51:02 +01:00
Daniel Schwabeneder 9a5f42c251 infinite shapes 2018-03-19 21:34:55 +01:00
Daniel Schwabeneder c8cdade884 :straightline for all backends 2018-03-19 16:24:23 +01:00
Daniel Schwabeneder bbff66a041 glvisualize() :straightline 2018-03-19 14:55:38 +01:00
Fedor Bezrukov 6b6394ba97 Fixed bug introduced into GR Polar plot 2018-03-19 03:15:14 +00:00
Daniel Schwabeneder d11c6a20bf Merge pull request #1438 from daschw/categorical-ticks
allow ticks = :all and ticks = n::Int for categorical axes
2018-03-18 23:21:44 +01:00
Daniel Schwabeneder 6c396e1d88 Merge pull request #1436 from daschw/fill-magic
fix fill magic argument
2018-03-18 23:21:16 +01:00
Daniel Schwabeneder bffd9bcb53 :straightline seriestype and gr implementation 2018-03-18 23:15:45 +01:00
Andrew Palugniok 7cee448d68 Merge pull request #1378 from apalugniok/dynamic-link-axes
Implement synchronized interactive linked axes for PyPlot and Plotly.
2018-03-18 19:48:09 +00:00
Fedor Bezrukov c273bf6a7b Partial attempt to fix label scaling to atomatically scientific notation.
Note, that the logic of replacing scientific notation in GR backend is a bit dodgy.
2018-03-18 17:57:27 +00:00
Daniel Schwabeneder 047a13a8dc Merge pull request #1430 from yakir12/patch-2
add option to supress saved message
2018-03-16 11:28:28 +01:00
Daniel Schwabeneder 717aed5a06 allow ticks = :all and ticks = n::Int for categorical axes 2018-03-16 11:26:56 +01:00
Daniel Schwabeneder 7d58090e59 use bar recipe in plotly 2018-03-16 09:36:24 +01:00
Daniel Schwabeneder 501df8cfb9 allow passing Real or 2Tuple of Reals as fillrange for Plotly 2018-03-15 21:46:19 +01:00
Daniel Schwabeneder 7f6fe09a00 fix magic fill argument 2018-03-15 21:22:29 +01:00
Andrew Palugniok d183d579cf Link axes before adding series. 2018-03-15 19:13:38 +01:00
Yakir Luc Gagnon bfa2fd2edc add option to supress saved message
Added option `show_msg::Bool` to `buildanimation` to show/suppress the "Saved animation to..." message.
2018-03-14 12:01:01 +01:00
Pietro Vertechi 7c257a09f6 Partially address #1409: group with named tuples (#1429)
* group with named tuples

* comma
2018-03-13 09:18:32 -06:00
Andrew Palugniok da4111579d Implement interactive linked axes for Plotly. 2018-03-07 15:09:25 +00:00
Andrew Palugniok 6b117234bc Implement interactive linked axes for PyPlot. 2018-03-07 15:09:25 +00:00
Daniel Schwabeneder c4bac660cf Merge pull request #1420 from daschw/contour-fix
Contour improvements
2018-03-01 19:59:09 +01:00
Michael Krabbe Borregaard ee2e7d509c Merge pull request #1419 from sglyon/sl/plotly_mime
ENH: provide "application/vnd.plotly.v1+json" for Plotly and PlotlyJS backends
2018-03-01 07:41:12 +01:00
Spencer Lyon 461e93fc56 ENH: provide "application/vnd.plotly.v1+json" for Plotly and PlotlyJS backends
For use in jupyterlab and nteract

closes #1418

closes #1386
2018-02-28 17:26:53 -05:00
Daniel Schwabeneder c74adc6521 check if a vector of the color black is passed to gr contour 2018-02-28 23:00:46 +01:00
Daniel Schwabeneder 7cc60d0b0c fix single-color case for plotly 2018-02-28 22:53:36 +01:00
Daniel Schwabeneder d8f0612f5a implement contour_labels and partially vector of colors for Plotly(JS) 2018-02-28 22:51:06 +01:00
Daniel Schwabeneder cd4b41a537 allow to pass a vector of colors for contour lines in PyPlot 2018-02-28 22:25:06 +01:00
Daniel Schwabeneder fdb2ee2847 implement contour_labels for PyPlot and fix #1091 2018-02-28 22:10:45 +01:00
Daniel Schwabeneder 9c4cc5acda GR colorbar fixees 2018-02-28 21:27:34 +01:00
Daniel Schwabeneder f901254519 add contour_labels attribute and minor GR contour fixes 2018-02-28 21:19:18 +01:00
Daniel Schwabeneder 18032bb9af Merge pull request #1414 from daschw/bar
default bar width for plots with only one bar (fix #1413)
2018-02-26 10:32:06 +01:00
Daniel Schwabeneder a7a5fe36f9 default to a bar width of _bar_width for bar plots with only one data point 2018-02-26 10:03:02 +01:00
Daniel Schwabeneder 32e1536955 Merge pull request #1411 from daschw/pyplot-marker
replace hline and vline marker shapes with _ and | on pyplot (fix #1188)
2018-02-26 09:15:55 +01:00
Daniel Schwabeneder 77c2ee6782 replace hline and vline marker shapes with _ and | on pyplot 2018-02-25 09:52:26 +01:00
Andrew Palugniok dbe5b78307 Merge pull request #1395 from apalugniok/native-ticks
Add :native option to ticks attribute (Fixes #1382)
2018-02-24 13:41:56 +00:00
Michael Krabbe Borregaard 9578fe03b9 Merge pull request #1408 from piever/plotlyjs
make plotlyjs use html in ijulia
2018-02-24 12:09:04 +01:00
piever ef48b66ac4 fix plotly 2018-02-24 01:55:59 +00:00
piever b9d586c009 make plotlyjs use html in ijulia 2018-02-24 01:35:30 +00:00
Andrew Palugniok 1d51982cb0 Fix non-native lims for ticks = :native on PyPlot. 2018-02-23 10:56:57 +00:00
Daniel Schwabeneder 046985277d Merge pull request #1399 from massemanet/fix-ijulia-integration
fix IJulia integration (fix #1365)
2018-02-23 11:44:16 +01:00
Daniel Schwabeneder d679337700 Merge pull request #1405 from daschw/contour
Make contourf work with uniform data
2018-02-23 11:01:56 +01:00
Daniel Schwabeneder 2d5f896069 Merge pull request #1403 from daschw/pyplot-colorbar
reduce pyplot colorbar size for z values with very small or big abs vals
2018-02-23 11:01:24 +01:00
Daniel Schwabeneder de51beebe8 ensure non-unique clims 2018-02-21 17:47:11 +01:00
Andrew Palugniok 80b25657bc Merge pull request #1401 from apalugniok/pgfplots-extra-brackets
Prevent addition of curly braces around style string. (Fixes #1396)
2018-02-21 16:09:46 +00:00
Daniel Schwabeneder 0db60348aa reduce pyplot colorbar size for z values with very small or big absolute values 2018-02-21 17:03:23 +01:00
Andrew Palugniok 5017024557 Fix handling of discrete values with ticks = :native for Plotly. 2018-02-21 14:50:32 +00:00
Andrew Palugniok 94863d69b1 Consider all ticks = false aliases in backends. 2018-02-21 10:17:13 +00:00
Andrew Palugniok 06466b060f Implement :native ticks option. 2018-02-21 10:09:57 +00:00
Daniel Schwabeneder 3ac9f3d9cc Merge pull request #1376 from grahamas/master
Allow animation frame saving frequency to be a variable.
2018-02-20 09:29:13 +01:00
Daniel Schwabeneder d335a0221d Merge pull request #1398 from daschw/time
add Dates.Time recipe (fix #1391)
2018-02-20 09:27:02 +01:00
Daniel Schwabeneder a118d73871 Merge pull request #1400 from daschw/step-ribbon
consider fillrange in step recipes (fix #1393)
2018-02-20 09:26:07 +01:00
Daniel Schwabeneder 6c13d87a00 remove old make_steps function 2018-02-18 22:59:37 +01:00
Daniel Schwabeneder 9e2264c841 consider fillrange in step recipes 2018-02-18 22:49:27 +01:00
Daniel Schwabeneder c0248069a1 add Dates.Time recipe 2018-02-17 23:33:55 +01:00
Andrew Palugniok 5ba4c10a18 Prevent addition of curly braces around style string. 2018-02-17 17:32:53 +00:00
mats cronqvist 82ceb71bd0 fix IJulia integration 2018-02-16 14:46:45 +01:00
Andrew Palugniok a4636fd88d Merge pull request #1390 from apalugniok/plotly-annotations
Fix misplaced Plotly annotations. (Fixes #1356)
2018-02-11 19:08:18 +00:00
Andrew Palugniok e19e25473c Fix misplaced Plotly annotations. 2018-02-11 10:36:12 +00:00
MA Laforge bde415edd7 Add support for Surface plots. 2018-02-06 06:26:07 -05:00
David Anthoff 2004090ce5 Remove GR clone in travis tests 2018-02-05 12:34:39 -08:00
David Anthoff 18ea542cc4 Add GR to REQUIRE 2018-02-05 09:21:06 -08:00
Graham A Smith 11a856fbb3 Allow animation frame saving frequency to be a variable. 2018-01-31 13:12:32 -06:00
Andrew Palugniok 1ed7899296 Merge pull request #1362 from apalugniok/cropped-image
Fix image axis limits and add image movement and resizing.
2018-01-19 15:41:41 +00:00
Andrew Palugniok a79a40b1e8 Allow manual flipping of yaxis for images. 2018-01-18 18:21:26 +00:00
Andrew Palugniok d4075a1ef5 Allow movement and resizing of images. 2018-01-18 16:23:39 +00:00
Andrew Palugniok 99f3b7ae99 Fix axis limits for images. 2018-01-18 16:23:39 +00:00
Daniel Schwabeneder fcb5b355b1 Merge pull request #1361 from daschw/group
fix grouping of series_annotations
2018-01-18 11:13:43 +01:00
Daniel Schwabeneder 43d26af34d Merge pull request #1360 from daschw/pyplot
Update pyplot backend
2018-01-18 11:06:27 +01:00
Daniel Schwabeneder 5e1c67c042 fix grouping of series_annotations 2018-01-18 10:44:35 +01:00
Daniel Schwabeneder 11ef2be506 update pyart3D 2018-01-17 15:18:36 +01:00
Andrew Palugniok 0f9bb7793c Merge pull request #1331 from apalugniok/subplot-labeling
RFC: Subplot labeling. Fixes #998
2018-01-15 23:02:40 +00:00
Daniel Schwabeneder decd7c2f60 Merge pull request #1354 from apalugniok/cropped-image
Fix axis limits not cropping image. Fixes #1296
2018-01-15 14:35:48 +01:00
Daniel Schwabeneder edf88ffdf6 Merge pull request #1353 from wkearn/wsk-bugfix-1329
Check if any of the iterator args are zero
2018-01-15 14:34:49 +01:00
Daniel Schwabeneder 435a7c809b Merge pull request #1352 from wkearn/wsk-bugfix-1823
Uncomment convertToAnyVector for Date/DateTime
2018-01-15 14:34:32 +01:00
Andrew Palugniok d79c66e5b6 Add position aliases. 2018-01-14 11:46:41 +00:00
Andrew Palugniok 10a8520805 Add subplot labeling via annotations. 2018-01-14 11:46:41 +00:00
Will Kearney cf6c16102b Use isempty rather than iszero 2018-01-13 13:57:03 -05:00
Will Kearney 32baaea5cb Check if any of the iterator args are zero
Fixes #1329
2018-01-13 11:20:33 -05:00
Andrew Palugniok 27e2795576 Fix deprecation. 2018-01-13 16:18:08 +00:00
Andrew Palugniok c21f3810b9 Fix axis limits not cropping image. 2018-01-13 15:44:52 +00:00
Will Kearney 877e7ab940 Uncomment convertToAnyVector for Date/DateTime
Fixes #1283
2018-01-13 10:07:27 -05:00
Daniel Schwabeneder 7a9a871be3 Merge pull request #1351 from daschw/gr-loglabels
gr: fix labels with logscales
2018-01-11 22:23:15 +01:00
Daniel Schwabeneder de31ce1c73 Merge pull request #1350 from daschw/tests
update version for tests
2018-01-11 22:16:59 +01:00
Daniel Schwabeneder 8b6dba8301 fix labels with logscales 2018-01-11 21:26:33 +01:00
Daniel Schwabeneder af859b4c13 update version in NEWS.md 2018-01-11 20:30:47 +01:00
Daniel Schwabeneder 9b5295ff00 update version for tests 2018-01-11 20:11:59 +01:00
Josef Heinen c1a94d704e Merge pull request #1349 from jheinen/master
fixed problems with labels in scientific notation
2018-01-11 03:45:24 +01:00
Josef Heinen c2b56878fc fixed problems with labels in scientific notation 2018-01-10 20:30:10 +01:00
Josef Heinen 4757bd89c0 Merge pull request #1249 from apalugniok/pgfplots-scaled-ticks
WIP: Fix scientific formatter for PGFPlots and GR. Fixes #1241
2018-01-10 19:05:13 +01:00
Michael Krabbe Borregaard 1e56bf939d Merge pull request #1347 from mkborregaard/master
update news for 0.14.3
2018-01-10 11:38:38 +01:00
Michael K. Borregaard dbd5ae46dd update news 2018-01-10 11:38:11 +01:00
Daniel Schwabeneder 7c6095b6e8 Merge pull request #1344 from daschw/heatmap-alpha
allow transparency in heatmaps (fix #1342)
2018-01-09 10:19:04 +02:00
Daniel Schwabeneder 04888646e7 fix gr 2018-01-08 13:50:16 +01:00
Daniel Schwabeneder f6ed3fbb76 allow transparency in heatmaps 2018-01-08 12:50:46 +01:00
Daniel Schwabeneder 7bf2918438 Merge pull request #1324 from wkearn/plotlyjs_rgba
Map rgba_string over :color vector and cycle through result
2018-01-08 12:44:47 +02:00
Daniel Schwabeneder 92fefc7089 Merge pull request #1340 from wkearn/framestyle_ticks
Add a check for ticks==nothing or false
2018-01-08 11:51:10 +02:00
Will Kearney e6df4d977d Add a check for ticks==nothing or false
Fixes #1336
2018-01-06 14:54:57 -05:00
Andrew Palugniok 62ca787e6e Fix scientific formatter for GR and PGFPlots. 2017-12-23 00:35:44 +00:00
Andrew Palugniok 32d59fff61 Turn off scaled ticks for PGFPlots. 2017-12-22 23:29:50 +00:00
Andrew Palugniok 1949b6fe0f Merge pull request #1330 from apalugniok/pyplot-alphaImages
Fix PyPlot ignoring alpha values of images. Fixes #1131
2017-12-19 14:19:32 +00:00
Andrew Palugniok 95a5b5025a Fix PyPlot ignoring alpha values of images 2017-12-19 12:05:11 +00:00
Daniel Schwabeneder aa22fd2ff2 Merge pull request #1328 from daschw/gr-grid3d
fix gr 3d grid appearance
2017-12-18 22:57:47 +01:00
Daniel Schwabeneder 50df9a70c9 fix gr 3d grid appearance 2017-12-18 22:15:57 +01:00
Michael Krabbe Borregaard 6d88e150d0 Merge pull request #1327 from mkborregaard/master
Don't return false from abline!
2017-12-18 09:20:36 +01:00
Michael K. Borregaard b1817e513b Don't return false 2017-12-18 09:19:31 +01:00
Michael Krabbe Borregaard ce737a9491 Merge pull request #1326 from mkborregaard/master
Don't add `abline!` if outside plot window
2017-12-18 09:17:36 +01:00
Michael K. Borregaard 6ff4dce62a Don't add abline! if outside plot window 2017-12-18 09:16:51 +01:00
Will Kearney 89b5582d0d Map rgba_string over :color vector and cycle through result 2017-12-17 16:13:35 -05:00
Daniel Schwabeneder 09c5e8a375 Merge pull request #1323 from daschw/plottheme
Reduce number of ticks in heatmap in showtheme recipe
2017-12-17 17:21:18 +01:00
Daniel Schwabeneder a1a7dcd6b8 reduce tick number in heatmap plot 2017-12-17 17:04:05 +01:00
Daniel Schwabeneder d223d872fb Merge pull request #1322 from daschw/line_z
Fix line_z
2017-12-17 17:01:28 +01:00
Andrew Palugniok 91eaa32ad7 Merge pull request #1320 from apalugniok/pyplot-legend
Fix mismatched legend color when linecolor is given. Fixes #1319
2017-12-17 16:00:08 +00:00
Daniel Schwabeneder 6cdccf4353 add missing 'series' 2017-12-17 16:44:20 +01:00
Josef Heinen ac9aee97fd Merge pull request #1318 from jheinen/master
gr: improve PNG output (resolution)
2017-12-17 13:07:16 +01:00
Josef Heinen 5be95be9ae gr: improve PNG output (resolution) 2017-12-17 12:52:20 +01:00
Andrew Palugniok e402f5dfce Fix mismatched legend color when linecolor is given. 2017-12-16 20:11:11 +00:00
Michael Krabbe Borregaard 61be113714 Merge pull request #1317 from apalugniok/3d-marker_z
3D marker_z handling. Fixes #1205
2017-12-16 10:08:13 +01:00
Andrew Palugniok a637f43edd Only base clims on z values when series is colored by z. 2017-12-15 22:49:46 +00:00
Daniel Schwabeneder 4bb43887a4 Merge pull request #1314 from daschw/showtheme
update showtheme recipe
2017-12-15 14:04:19 +01:00
Daniel Schwabeneder 802b20be6f update showtheme recipe 2017-12-15 10:30:56 +01:00
Michael K. Borregaard 216a9c3666 reactivate precompilation 2017-12-15 09:24:00 +01:00
Michael K. Borregaard d52b2a9adc update news 2017-12-15 09:22:20 +01:00
Michael K. Borregaard 81782c3927 turn off precompilation 2017-12-15 09:18:37 +01:00
Michael Krabbe Borregaard 2c2ebbba0e Merge pull request #1313 from joshday/jd/fix-histogram
Fix plotly histogram
2017-12-15 09:15:06 +01:00
Josh Day 3d323a734d fix plotly histogram 2017-12-15 00:22:05 -05:00
Michael Krabbe Borregaard 93263a61b1 Merge pull request #1301 from JuliaPlots/sd/fixlines
fix JuliaGL/GLVisualize.jl#238
2017-12-15 05:04:38 +01:00
Michael Krabbe Borregaard 8b551e5285 Merge pull request #1311 from apalugniok/ribbons
Fix ribbons slicing for several series. Fixes #1302
2017-12-14 22:13:44 +01:00
Michael Krabbe Borregaard e11c91ddd9 Merge pull request #1308 from rdeits/line-z-example
add line_z and marker_z example
2017-12-14 22:05:30 +01:00
Andrew Palugniok 938c83533b Fix slicing of ribbons. 2017-12-14 19:25:59 +00:00
Daniel Schwabeneder 46136d616f Merge pull request #1310 from daschw/release
precompile on
2017-12-14 11:33:19 +01:00
Daniel Schwabeneder 8fe902e96c precompile on 2017-12-14 11:29:55 +01:00
Daniel Schwabeneder 2fb7dddffb Merge pull request #1309 from daschw/release
prepare release
2017-12-14 11:25:30 +01:00
Daniel Schwabeneder 5d1876ab6d precompile off 2017-12-14 11:03:52 +01:00
Daniel Schwabeneder 1aa4e7eee6 update news.md 2017-12-14 11:02:59 +01:00
Daniel Schwabeneder 995e12bd57 Merge pull request #1279 from daschw/plottheme
New PlotTheme type
2017-12-14 09:38:49 +01:00
Robin Deits 349b6e8254 fix typo 2017-12-13 18:59:15 -05:00
Robin Deits ee6dbb9ac7 add line_z and marker_z example 2017-12-13 18:55:48 -05:00
Daniel Schwabeneder 5b85cd83f2 Merge pull request #1307 from wkearn/pyplot_legend_style
Add linestyle argument to the legend
2017-12-13 22:27:59 +01:00
Will Kearney 1645c3f66b Add linestyle argument to the legend
This fixes #1305
2017-12-13 15:07:54 -05:00
Michael Krabbe Borregaard 084d45141d Merge pull request #1304 from joshday/jd/histogram
plotly: bar_width and stroke_width support for bar plots
2017-12-12 21:50:45 +01:00
Josh Day 50bec7a461 cleanup 2017-12-12 15:18:17 -05:00
Josh Day f80afddd8f add strokewidth and bar_width for plotly's bar 2017-12-12 15:15:12 -05:00
Andrew Palugniok 5d2c630b05 Merge pull request #1299 from apalugniok/gr-logticks
Fix default log scale ticks in GR backend. Fixes #1203
2017-12-12 17:37:07 +00:00
Andrew Palugniok f655b2313c Fix default log scale ticks in GR backend. 2017-12-12 16:45:26 +00:00
SimonDanisch 2a819c2849 fix JuliaGL/GLVisualize.jl#238 2017-12-11 12:34:21 +01:00
Michael Krabbe Borregaard 0ef13dcf7a Merge pull request #1300 from mkborregaard/master
RFC: abline! does not change axis limits; fix: #1297
2017-12-11 12:12:52 +01:00
Michael K. Borregaard 5e5f3c1e95 abline! does not change axis limits 2017-12-11 10:26:33 +01:00
Daniel Schwabeneder c76ca2dd6e add showtheme recipe 2017-12-11 09:27:02 +01:00
Daniel Schwabeneder ab490b8f95 Merge pull request #1295 from wkearn/font_bugfix
Use the :fontsize keys so the scalefontsizes command works
2017-12-08 09:52:17 +01:00
Will Kearney bd42d9e7cc Use the :fontsize labels so the scalefontsizes command works
Fixes #1294
2017-12-07 20:56:54 -05:00
Michael Krabbe Borregaard e3d8f4a223 Merge pull request #1291 from mkborregaard/postrelease
reactivate precompilation
2017-12-07 13:13:57 +01:00
Michael K. Borregaard 34567e1282 reactivate precompilation 2017-12-07 13:12:02 +01:00
Michael Krabbe Borregaard acfb14a1f5 Merge pull request #1289 from mkborregaard/master
update news
2017-12-07 13:11:03 +01:00
Michael K. Borregaard 6a3495819a update news 2017-12-07 13:10:26 +01:00
Michael Krabbe Borregaard bf6e8d3c1f Merge pull request #1288 from mkborregaard/add-scatterpath
added scatterpath series recipe
2017-12-07 12:04:08 +01:00
Michael Krabbe Borregaard 66f08cc1a3 fix typo on docstring 2017-12-07 08:52:09 +01:00
Michael Krabbe Borregaard 470012501b Merge pull request #1286 from mforets/patch-1
say how to get the list of attributes in `?plot`
2017-12-07 08:51:19 +01:00
Marcelo Forets 986bd02e5e Update plot.jl 2017-12-06 22:33:47 -03:00
Michael K. Borregaard 9b8510ab3e added scatterpath series recipe 2017-12-06 23:19:35 +01:00
Marcelo Forets 0db9710e0f say how to get the list of attributes in ?plot 2017-12-06 17:46:35 -03:00
Michael Krabbe Borregaard 7f231057fd Merge pull request #1284 from JuliaPlots/tbreloff-patch-1
change author section
2017-12-06 07:01:26 +01:00
Tom Breloff bb687e47cc change author section 2017-12-05 21:14:08 -05:00
Daniel Schwabeneder 0f3928ec9a fix kw support 2017-12-05 22:29:56 +01:00
Daniel Schwabeneder a8380334df fix kw support 2017-12-05 22:28:22 +01:00
Daniel Schwabeneder 70bead1eb1 support old PlotTheme type 2017-12-05 22:09:18 +01:00
Michael Krabbe Borregaard df63530b89 Merge pull request #1282 from wkearn/wsk/scale-fix
Update iterator properly in _subplot_setup
2017-12-05 20:44:08 +01:00
Daniel Schwabeneder 34dedd36e6 Merge pull request #1281 from hayatoikoma/fix_grayimg
Fix the display of an grayscale image for image-nonsupported backends
2017-12-05 19:43:38 +01:00
Will Kearney eb6c15caba Update iterator properly
This seems to fix #1266
2017-12-05 13:12:10 -05:00
Hayato Ikoma 39a7815f80 Fix the display of an grayscale image for image-nonsupported backends 2017-12-05 08:54:54 -08:00
Daniel Schwabeneder 4bbe367aab Merge pull request #1278 from JackDevine/master
Examples are limited to 90 columns.
2017-12-05 16:53:41 +01:00
Daniel Schwabeneder 7d50c7e4fe Merge pull request #1280 from daschw/default-magic
Default magic
2017-12-05 16:51:49 +01:00
JackDevine 5d0adb1783 Add comma 2017-12-05 08:36:04 +13:00
Daniel Schwabeneder 81ef4bdee8 remove _magic_arguments 2017-12-04 19:45:21 +01:00
Daniel Schwabeneder 2cf365d36d Allow magic arguments in default() 2017-12-04 19:34:02 +01:00
Daniel Schwabeneder 22d8ecffe5 fix typo 2017-12-04 15:53:45 +01:00
Daniel Schwabeneder b987331b4f update new heme() function 2017-12-04 14:54:35 +01:00
Jack Devine eff8159d46 Merge branch 'master' into master 2017-12-04 22:44:31 +13:00
Jack Devine f0e4f4dc9d Merge branch 'master' into master 2017-12-04 22:42:26 +13:00
JackDevine e02a70249e Examples are limited to 90 columns.
Thanks @daschw for pointing out the correct place to make these
changes. I have also changed the explanation texts, which may be a
little overkill, but I do think that the style guides apply to Markdown
string too (could be wrong though).
2017-12-04 22:34:45 +13:00
Daniel Schwabeneder 899afd625a add new heme() function 2017-12-04 09:16:00 +01:00
Daniel Schwabeneder 863ec08681 Merge pull request #1274 from daschw/pyplot-framestyle_grid
PyPlot: set tick marks color to match grid color for framestyle = :grid
2017-12-02 10:16:08 +01:00
Daniel Schwabeneder 28c958fb20 set tick marks color to grid color for framestyle = :grid 2017-12-01 16:14:59 +01:00
Daniel Schwabeneder 4c9f4a55d5 Merge pull request #1271 from daschw/gr-legend
allow to change the foreground_color_legend in gr
2017-11-30 16:50:18 +01:00
Daniel Schwabeneder a7fcf77251 allow to change the foreground_color_legend in gr 2017-11-30 16:26:48 +01:00
Daniel Schwabeneder a57745ed64 Merge pull request #1270 from daschw/grid
Extend grid lines to axes limits for GR (and GLVisualize)
2017-11-30 13:00:48 +01:00
Daniel Schwabeneder dd16c7d560 extend grid lines to axes limits 2017-11-30 11:47:20 +01:00
Daniel Schwabeneder 7f3780a20d Merge pull request #1269 from daschw/tests
use new StatPlots df syntax in testexamples
2017-11-30 11:16:10 +01:00
Daniel Schwabeneder 99c8713e7f Merge pull request #1268 from daschw/contour-fill
fix axes limits for fill=true in 3d plots (fix #1267)
2017-11-30 11:15:53 +01:00
Daniel Schwabeneder 49eb2c426d update testexample 30 2017-11-30 11:05:05 +01:00
Daniel Schwabeneder 4c55ff5df8 use new StatPlots df syntax in testexamples 2017-11-30 11:01:12 +01:00
Daniel Schwabeneder 714f8dea1d fix axes limits for fill=true in 3d plots 2017-11-30 09:45:09 +01:00
Josef Heinen 1419a919aa Merge pull request #1260 from jheinen/master
gr: added support for non-string legend labels
2017-11-22 21:46:38 +01:00
Josef Heinen 6d4717fc96 gr: added support for non-string legend labels 2017-11-22 21:26:53 +01:00
Josef Heinen 6a8f4caee3 Merge pull request #1258 from jheinen/master
gr: fix 'hidden window' problem after savefig
2017-11-21 14:58:12 +01:00
Josef Heinen dbf96a69d7 gr: fix 'hidden window' problem after savefig 2017-11-21 14:45:00 +01:00
Daniel Schwabeneder 0519f18bd7 Merge pull request #1257 from daschw/pyplot-fonts
fix guidefontamily typo in pyplot
2017-11-20 16:56:38 +01:00
Daniel Schwabeneder f7765c80b8 fix guidefontamily typo in pyplot 2017-11-20 16:54:05 +01:00
Daniel Schwabeneder f2e2ffa170 Merge pull request #1255 from daschw/fonts
Allow setting fonts in recipes (fix #555)
2017-11-20 15:17:33 +01:00
Daniel Schwabeneder b2a816452d Merge pull request #1242 from biggsbiggsby/patch-1
Generate a palette for each gif frame; Fixes #1239
2017-11-20 11:01:28 +01:00
Daniel Schwabeneder 299e9a85f2 Merge pull request #1253 from romainFr/pull-request/c01d8199
Plotly : always define range explicitely. Solves axis linking #1124
2017-11-20 08:40:12 +01:00
Daniel Schwabeneder ad34863bd6 Merge pull request #1254 from daschw/axes-limits
expand axes extrema for heatmap edges
2017-11-20 08:40:01 +01:00
Daniel Schwabeneder 129a91b36f update arg description 2017-11-19 21:18:04 +01:00
Daniel Schwabeneder 78f10de8cd update inspectdr 2017-11-19 20:44:22 +01:00
Daniel Schwabeneder 189b2e5cd6 update glvisualize 2017-11-19 20:36:26 +01:00
Daniel Schwabeneder d4f67ec3b5 update glvisualize 2017-11-19 20:31:28 +01:00
Daniel Schwabeneder 7ec54b9c2e update plotly(js) 2017-11-19 19:54:52 +01:00
Daniel Schwabeneder 60d20ea998 update pyplot 2017-11-19 18:15:22 +01:00
Daniel Schwabeneder e80a73cc1c fix magic font argument and cascading font defaults 2017-11-19 16:59:54 +01:00
Daniel Schwabeneder 6e51a08694 fix errors 2017-11-19 15:36:11 +01:00
Daniel Schwabeneder 0da6f6b4a4 update gr 2017-11-19 15:32:30 +01:00
Daniel Schwabeneder ba3e75e710 fix errors 2017-11-19 15:16:49 +01:00
Daniel Schwabeneder 8fee5e0de7 implement titlefont legendfont tickfont and guidefont functions to construct font objects from subplots and axes 2017-11-19 14:58:30 +01:00
Daniel Schwabeneder 68a060b7eb implement titlefont, legendfont, tickfont and guidefont magic keyword arguments 2017-11-19 14:31:30 +01:00
Daniel Schwabeneder 9f5be974b6 add fontfamily, fontsize, fonthalign, fontvalign, fontrotation, fontcolor keywords 2017-11-19 14:02:49 +01:00
Daniel Schwabeneder ea976d5f08 expand axes extrema for heatmap edges 2017-11-19 12:53:11 +01:00
Daniel Schwabeneder 892d68e792 Merge pull request #1251 from daschw/pyplot-legend
PyPlot: change legend symbols for shapes and filled plots
2017-11-18 08:43:23 +01:00
Romain Franconville 5a0744e2f1 Remove commented code 2017-11-17 16:06:14 -05:00
Romain Franconville c01d8199f9 Also include scaling 2017-11-17 15:29:55 -05:00
Romain Franconville df023d6bdb Always define axis range explicitely 2017-11-17 15:02:16 -05:00
Daniel Schwabeneder 4bfb562477 remove extra space 2017-11-17 13:01:13 +01:00
Daniel Schwabeneder 4bc01b92bd avoid too big linewidths in legend 2017-11-17 12:59:20 +01:00
biggsbiggsby ee0f4e11ea Update animation.jl
Changed palette for each frame to an option, made the default palette a lossless bmp file for best quality/filesize, but still compatible with FFMPEG 3.4 on Win7 x64
2017-11-17 12:35:36 +01:00
Daniel Schwabeneder 1aa780f0a2 change legend symbols for shapes and filled plots on pyplot 2017-11-17 11:33:10 +01:00
biggsbiggsby cf58f3cbf2 Update animation.jl
Generates a color palette for each frame (instead of each animation) to improve quality, and avoid palette file format issues in FFMPEG 3.4
2017-11-17 10:30:23 +01:00
Michael Krabbe Borregaard 18619e9010 Merge pull request #1246 from huckl3b3rry87/pull-request/ae37dce0
allow legend to be outside for pgfplots()
2017-11-14 20:33:20 +00:00
Huckleberry Febbo ae37dce0f3 allow legend to be outside for pgfplots() 2017-11-14 13:43:17 -05:00
Michael Krabbe Borregaard e48831d092 Merge pull request #1243 from apalugniok/polar-output
Correct polar tick alignment for PGFPlots.
2017-11-14 15:05:15 +01:00
Andrew Palugniok 99f25ef744 Fix typo. 2017-11-14 13:49:53 +00:00
biggsbiggsby acf6e86c0f gif animation.jl
Change palette from png to gif to avoid png encoding bug in ffmpeg
2017-11-14 09:39:59 +01:00
Michael Krabbe Borregaard 19192b622b Merge pull request #1224 from hessammehr/master
Fix for #1138
2017-11-13 17:06:03 +01:00
Michael Krabbe Borregaard 183f399341 Merge pull request #1208 from apalugniok/polar-output
Polar plots consistency
2017-11-13 05:17:46 +01:00
Andrew Palugniok 240c1efab9 Improve default radial axis padding. 2017-11-12 18:09:08 +00:00
Andrew Palugniok 8bbdb0f1b8 Adds radial data filtering for points within axis limits. 2017-11-12 18:08:40 +00:00
Daniel Schwabeneder ecee135a63 Merge pull request #1230 from daschw/pgfplots-legend-symbols
change pgfplots legend symbol for shapes and filled plots (fix #1215)
2017-11-09 09:57:43 +01:00
Daniel Schwabeneder 51d4630405 change pgfplots legend symbol for shapes and filled plots 2017-11-08 22:02:40 +01:00
Michael Krabbe Borregaard 60e7695546 Merge pull request #1228 from PallHaraldsson/patch-1
Typo?
2017-11-07 12:29:10 +01:00
Páll Haraldsson 6d14a858a3 Typo?
Guessing here, 0.2.0 must be really old?
2017-11-07 11:11:46 +00:00
Andrew Palugniok 08a6f3af36 Allow custom radial ticks for GR. Fix polar ylims for non-zero ymin values in GR. 2017-11-05 10:37:51 +00:00
Andrew Palugniok cc43202e8f Fix radial axis tick alignment for GR. 2017-11-04 23:04:49 +00:00
Hessam Mehr 8fb3f3b1c9 Fixed for #1138 2017-11-04 15:20:41 -07:00
Andrew Palugniok 2fe2ff474c Implement grid attributes for polar plots. 2017-11-04 21:27:02 +00:00
Andrew Palugniok f0ad851aa7 Make radial axis vertical. 2017-11-03 19:45:17 +00:00
Daniel Schwabeneder ab29a712c0 Merge pull request #1221 from daschw/gr-contour-lw
allow setting the linewidth for contour plots in GR
2017-11-03 11:50:30 +01:00
Daniel Schwabeneder 8dd264c4da remove unnecessary line 2017-11-03 10:15:55 +01:00
Daniel Schwabeneder 40282ae23a allow setting the linestyle for contours on GR 2017-11-03 10:02:16 +01:00
Josef Heinen ed75369c6d Merge pull request #1220 from jheinen/master
gr: use correct aspect ratio (fixes #1219)
2017-11-02 22:15:30 +01:00
Josef Heinen b34f4141a2 Update gr.jl 2017-11-02 21:53:11 +01:00
Daniel Schwabeneder 5d5d8f073a allow setting the linewidth for contour plots in GR 2017-11-02 20:38:06 +01:00
Josef Heinen f690961af2 gr: use correct aspect ratio (fixes #1219) 2017-11-02 20:12:11 +01:00
Andrew Palugniok 12aa43ff5f Fix deprecations. 2017-11-02 16:33:05 +00:00
Andrew Palugniok 4f171e3eb5 Add handling of polar axes. 2017-11-02 16:32:57 +00:00
Daniel Schwabeneder 671f5c3a68 Merge pull request #1213 from daschw/fillrange
Make `fill = true` fill to zero
2017-10-31 09:21:47 +01:00
Daniel Schwabeneder 1f12185441 Merge pull request #1214 from apalugniok/plotly-colorbar
Fix colorbar always displaying in Plotly. (Fixes #1211)
2017-10-31 09:21:31 +01:00
Andrew Palugniok a3e599e38d Fix colorbar always displaying in Plotly. 2017-10-30 19:50:02 +00:00
Daniel Schwabeneder 5a3779e431 fill = true fills to 0 2017-10-30 10:49:22 +01:00
Michael Krabbe Borregaard 5ddcdef1b4 Merge pull request #1210 from mkborregaard/master
add hline marker to pgfplots
2017-10-27 19:22:11 +02:00
Michael K. Borregaard 7b6b44b284 add hline to pgfplots 2017-10-27 15:52:32 +02:00
Michael Krabbe Borregaard a691d5c7e8 Merge pull request #1187 from anowacki/movie-compatibility
Animations: improve movie compatibility when using ffmpeg
2017-10-25 11:44:03 +02:00
Josef Heinen 7cf40b16df Merge pull request #1206 from jheinen/master
gr: implement title location
2017-10-24 20:06:00 +02:00
Josef Heinen ad6b707abf gr: implement title location 2017-10-24 19:50:18 +02:00
Andy Nowacki 133052b58c Animations: improve movie compatibility when using ffmpeg
Add the -pix_fmt yuv420p option when using ffmpeg to save
animations with the mov or mp4 commands. This improves
compatibility of the movie files since many players do not
support the ffmpeg defaults.

To do this, add a third positional argument to `buildanimation`
to specify if we want an animated GIF file.  The default
is `true`.

See the following for more information:
- https://trac.ffmpeg.org/wiki/Encode/H.264 ('Compatibility')
- https://apple.stackexchange.com/questions/166553/why-wont-video-from-ffmpeg-show-in-quicktime-imovie-or-quick-preview
2017-10-23 14:16:12 +01:00
Michael Krabbe Borregaard 226bf7e705 Merge pull request #1199 from mkborregaard/make-revise-possible
Make revise possible
2017-10-21 07:40:53 +02:00
Michael K. Borregaard cdcbdc308c include backend files 2017-10-20 22:45:04 +02:00
Daniel Schwabeneder 5bfa6151ac Merge pull request #1195 from apalugniok/pgfplots-logticks
Fix log scale ticks LaTeX error for PGFPlots. (fixes #1192)
2017-10-19 17:38:44 +02:00
Daniel Schwabeneder 020760f0c8 Merge pull request #1190 from daschw/tests
Minor test_example changes (close #1162)
2017-10-19 17:38:25 +02:00
Andrew Palugniok 0c4750547a Fix LaTeX error for log scale ticks. 2017-10-19 15:30:45 +01:00
Michael Krabbe Borregaard 9c46509f84 Merge pull request #1185 from H-M-H/animation_fix
Use ffmpeg & palette to create gifs, closes #1050
2017-10-18 22:28:56 +02:00
Daniel Schwabeneder 928a2d646b Merge pull request #1189 from daschw/spy
use fg_color for matrices with unique non-zeros in spy recipe
2017-10-18 21:31:54 +02:00
Daniel Schwabeneder 7ffd1fc9c2 some further improvements for framestyle and group testexamples 2017-10-18 21:24:28 +02:00
Daniel Schwabeneder 6d4f456826 fix framestyle testexample 2017-10-18 21:06:37 +02:00
Daniel Schwabeneder e78bf87377 update some test_examples 2017-10-18 20:51:43 +02:00
Daniel Schwabeneder c76fc5b909 use fg_color for matrices with unique non-zeros in spy recipe 2017-10-18 20:47:06 +02:00
Michael Krabbe Borregaard eecd14f53a Merge pull request #1036 from JuliaPlots/fbot/deps
Fix deprecations
2017-10-17 21:45:13 +02:00
femtocleaner[bot] ef29b4a5b0 Fix deprecations 2017-10-17 09:59:09 +00:00
Daniel Schwabeneder d6748792e9 Merge pull request #1184 from daschw/gr-box-flip
fix combination of box framestyle and flip on gr
2017-10-17 09:23:47 +02:00
Daniel Schwabeneder ae9c26504d Merge pull request #1183 from daschw/spy
spy recipe: change default color for matrices with unique values
2017-10-17 09:23:25 +02:00
HMH 7f7b543e18 Use ffmpeg & palette to create gifs, closes #1050
First let ffmpeg generate a colorpalette so it uses the limited amount
of colors available properly and only then create the actual gif using
the generated palette. This replaces convert completely as it yields far
worse results for long gifs and is considerably slower.
2017-10-16 23:53:00 +02:00
Daniel Schwabeneder 2464d7bd9a fix combination of box framestyle and flip on gr 2017-10-16 21:46:23 +02:00
Daniel Schwabeneder 3ce71999e2 spy recipe: change default color for matrices with unique values 2017-10-16 21:24:13 +02:00
Daniel Schwabeneder 7f9d83c088 Merge pull request #1168 from darwindarak/dd/reset-defaults
RFC: Add (back?) ability to reset defaults
2017-10-16 20:17:02 +02:00
Daniel Schwabeneder e8f6e7b56c Merge pull request #1181 from daschw/colorbar
Fix GR annotations with colorbar (fix #1179)
2017-10-16 19:19:03 +02:00
Daniel Schwabeneder 94c0957e11 draw colorbar in the end 2017-10-16 18:04:46 +02:00
Michael Krabbe Borregaard b0ffe03c99 Merge pull request #1178 from JuliaPlots/patch-appveyor-readme
Fix appveyor badge
2017-10-15 13:01:03 +02:00
Michael Krabbe Borregaard 8ea878a2a2 Fix appveyor badge 2017-10-15 12:43:15 +02:00
Michael Krabbe Borregaard bbbab914d8 Merge pull request #1177 from JuliaPlots/revert-1176-no_copy
Revert "Don't copy input arguments - fix #1175"
2017-10-14 22:56:12 +02:00
Michael Krabbe Borregaard 735a45b4e9 Revert "Don't copy input arguments - fix #1175" 2017-10-14 22:55:23 +02:00
Michael Krabbe Borregaard a4558302f2 Merge pull request #1176 from mkborregaard/no_copy
Don't copy input arguments - fix #1175
2017-10-14 22:39:00 +02:00
Michael K. Borregaard d8ba26f790 Don't copy input arguments into d 2017-10-14 08:52:51 +02:00
Michael Krabbe Borregaard dcc3055dec Merge pull request #1174 from mkborregaard/fix_hist_weights
fix `weights` in `histogram`; closes #1173
2017-10-13 17:09:06 +02:00
Michael K. Borregaard 6db7116db9 add weights argument to histogram example 2017-10-13 17:08:26 +02:00
Michael K. Borregaard 422988b3f6 fix weights in histogram 2017-10-13 12:38:56 +02:00
Michael Krabbe Borregaard 2f04c5fec8 Merge pull request #1141 from apalugniok/apalugniok-test2
Adds camera attribute for 3D plots.
2017-10-13 00:26:39 +02:00
Pietro Vertechi e811aa44b0 Merge pull request #1164 from piever/svg
fix #750 : save svg plotlyjs
2017-10-12 14:09:41 +01:00
Darwin Darakananda 4c7ab232d5 Add (back?) ability to reset defaults 2017-10-11 10:25:54 -07:00
Daniel Schwabeneder fc42641469 Merge pull request #1163 from daschw/gr-flip
fix flip for GR
2017-10-11 14:53:40 +02:00
Michael Krabbe Borregaard b71cfce105 Merge pull request #1155 from mkborregaard/newspy
RFC: New spy implementation
2017-10-11 09:01:58 +02:00
Pietro Vertechi be55c1ad6f save svg plotlyjs 2017-10-10 23:29:18 +01:00
Daniel Schwabeneder 979a846298 fix flip for GR 2017-10-10 23:26:39 +02:00
Daniel Schwabeneder a4c59ce964 Merge pull request #1153 from daschw/gr-marker_z
Fix marker_z for 3D plots on GR (test example 24) (fix #1152)
2017-10-10 21:06:01 +02:00
Daniel Schwabeneder 208c70f933 Merge pull request #1161 from daschw/tests
update version for tests
2017-10-10 19:51:47 +02:00
Daniel Schwabeneder 9dcbc06b3d update version for tests 2017-10-10 19:50:45 +02:00
Josef Heinen e3f6da382d Merge pull request #1158 from jheinen/master
gr: fixed colorbar problem for flipped axes
2017-10-10 12:20:49 +02:00
Josef Heinen cc201ce4e7 gr: fixed colorbar problem for flipped axes 2017-10-10 10:54:29 +02:00
Michael K. Borregaard 08bdd11410 New spy implementation 2017-10-09 21:19:32 +02:00
Daniel Schwabeneder bac192d825 remove unnecessary lines 2017-10-09 17:20:36 +02:00
Daniel Schwabeneder 55c968f138 fix marker_z for 3D plots - draw colorbar once per series 2017-10-09 17:13:44 +02:00
Andrew Palugniok 6df2bc2790 Clarify gr.jl setspace() rounding syntax. 2017-10-09 11:40:04 +01:00
Andrew Palugniok f8576c7135 Remove :view alias for :camera attribute. 2017-10-09 11:33:24 +01:00
Daniel Schwabeneder 7d220f571d Merge pull request #1142 from daschw/line_z
Fix linestyle on GR (fix #1139)(fix #1123)
2017-10-08 13:50:43 +02:00
Christopher Rackauckas eda1ebe36b Fix docs link
Ugh, flubbed that one. There's the `http://`
2017-10-07 13:24:03 -07:00
Christopher Rackauckas ae4288719f Merge pull request #1145 from JuliaPlots/ChrisRackauckas-patch-3
New docs page link
2017-10-07 13:22:53 -07:00
Christopher Rackauckas a016b655f4 New docs page link 2017-10-07 13:06:08 -07:00
Andrew Palugniok f4bc2e0649 Convert :camera attribute input for GR. 2017-10-07 20:05:53 +01:00
Andrew Palugniok cf6f7035b6 Added extra :camera aliases. 2017-10-07 20:05:05 +01:00
Daniel Schwabeneder cb7498a30d fix linestyle on gr 2017-10-07 21:02:14 +02:00
Andrew Palugniok ccb3cadd2a Implemented camera attribute for Plotly/PlotlyJS. 2017-10-06 20:47:04 +01:00
Andrew Palugniok 0fb1a0ed6b Implemented camera attribute for PGFPlots. 2017-10-06 20:47:04 +01:00
Andrew Palugniok 94e79f1e4c Implemented camera attribute for PyPlot. 2017-10-06 20:46:25 +01:00
Andrew Palugniok 65a28e76e5 Implemented camera attribute for GR. 2017-10-06 20:46:25 +01:00
Andrew Palugniok 0c5a9172ab Added camera attribute processing. 2017-10-06 20:46:25 +01:00
Daniel Schwabeneder 1c21a0d609 Merge pull request #1132 from darwindarak/dd/pyplot-linez
RFC: Fix `line_z` for PyPlot backend (fix #1021)
2017-10-06 09:24:57 +02:00
Darwin Darakananda 16d18552f8 Allow line_z to specify color across multiple lines 2017-10-05 20:49:17 -07:00
Daniel Schwabeneder 001cb80cfe Merge pull request #1120 from daschw/axis-false
showaxis attribute
2017-10-05 23:17:55 +02:00
Daniel Schwabeneder bd14d9c07b Merge pull request #1108 from AnkurD/colorbar
Colorbar takes font style from Y Axis
2017-10-05 13:58:41 +02:00
Michael Krabbe Borregaard 08bbde327f Merge pull request #1135 from mkborregaard/drop-travis-pyplot
Drop tests for pyplot (temporarily)
2017-10-05 13:42:45 +02:00
Michael K. Borregaard 12488bf2b0 Drop tests for pyplot (temporarily)
revisit 12 oct
2017-10-05 13:24:21 +02:00
Michael Krabbe Borregaard 4bf0d69f79 Merge pull request #1133 from JackDevine/legend-markers
PyPlot legends now show marker types.
2017-10-05 12:58:02 +02:00
Michael K. Borregaard 78e3b69cc5 prec 2017-10-05 12:30:29 +02:00
Michael K. Borregaard 531a38bc39 no prec 2017-10-05 12:28:52 +02:00
Michael K. Borregaard 77fa5454e2 remember backticks 2017-10-05 12:27:51 +02:00
Michael Krabbe Borregaard 0cd382a1ce Merge pull request #1129 from mkborregaard/fix-function-vector
Apply automatic limits for vectors of functions
2017-10-05 12:26:04 +02:00
Michael K. Borregaard 9fc0c98722 precompile 2017-10-05 12:25:04 +02:00
Michael Krabbe Borregaard af23074820 Merge pull request #1134 from mkborregaard/patch-release
ready for release
2017-10-05 12:22:52 +02:00
Michael K. Borregaard fdf2d5b20b ready for release 2017-10-05 12:22:12 +02:00
Michael K. Borregaard b37f2141a1 Also import px and pct into PlotMeasures
Necessary for example 29 to work
2017-10-05 12:12:54 +02:00
JackDevine 520dc80eeb Added marker strokes 2017-10-05 22:58:18 +13:00
JackDevine 878fa48afa PyPlot legends now show marker types. 2017-10-05 21:35:38 +13:00
Darwin Darakananda 514cd1bd37 normalize colors even when plotting without colorbars 2017-10-04 15:10:36 -07:00
Darwin Darakananda f5ee5ea814 Fix line_z for PyPlot backend
`LineCollection` expects an array with pairs of coordinates,
corresponding to the starting and ending points of each segment.
2017-10-04 14:26:35 -07:00
Daniel Schwabeneder e3b0f7cd94 pgfplots: remove axis arrows and implement origin and zerolines framestyles 2017-10-04 13:40:56 +02:00
Michael K. Borregaard 5567038cec simplify 2017-10-04 11:47:20 +02:00
Michael K. Borregaard 0327c9101e slight refactor for clarity 2017-10-04 11:44:20 +02:00
Michael K. Borregaard 3d86d5f530 Apply automatic limits for vectors of functions 2017-10-04 11:38:32 +02:00
Michael K. Borregaard 073724a84c reactivate 2017-10-03 15:14:10 +02:00
Michael Krabbe Borregaard 6a129bfe92 Merge pull request #1128 from mkborregaard/hotfix-measures
Make Measures available in Plots in general too
2017-10-03 15:12:27 +02:00
Michael K. Borregaard 53a4c36aab Make Measures available in Plots in general too 2017-10-03 15:12:01 +02:00
Michael Krabbe Borregaard eb36f4eca0 Merge pull request #1127 from mkborregaard/release-13
Reactivate precompilation
2017-10-03 10:31:29 +02:00
Michael K. Borregaard 54838d386d Reactivate precompilation 2017-10-03 10:31:05 +02:00
Michael Krabbe Borregaard 0235821f24 Merge pull request #1126 from mkborregaard/release-13
release-0.13
2017-10-03 10:29:39 +02:00
Michael K. Borregaard efd116ec52 deactivate precompilation 2017-10-03 10:29:06 +02:00
Michael K. Borregaard ff0f1c5c50 update news.md 2017-10-03 10:28:54 +02:00
Michael Krabbe Borregaard 6bbb26d2ea Merge pull request #855 from mkborregaard/submodule-measure
Add submodule PlotMeasures (fix #821)
2017-10-02 15:20:41 +02:00
Michael K. Borregaard 2a1140c0b3 include PlotMeasures in example 29 2017-10-02 15:07:16 +02:00
Michael Krabbe Borregaard a80c7ada27 Merge pull request #1116 from jw3126/replaceD
replace d by plotattributes inside recipes
2017-10-02 14:46:11 +02:00
Michael Krabbe Borregaard 9bc6d0c7d1 Merge pull request #1122 from mkborregaard/bar_width_fix
Fix barwidth to minimum(diff) not mean(diff)
2017-10-02 11:16:25 +02:00
Michael K. Borregaard f3566a4933 sort before taking diff 2017-10-02 10:02:39 +02:00
Michael K. Borregaard cd958a6c68 Fix barwidth to minimum(diff) not mean(diff) 2017-10-02 08:53:41 +02:00
Michael K. Borregaard 4f6a920f72 Import Measures into Plots 2017-10-02 08:28:25 +02:00
Michael K. Borregaard b717cf1dc0 Rename submodule to PlotMeasures 2017-10-02 08:24:59 +02:00
Michael K. Borregaard 33e5a51a28 add submodule Measure 2017-10-02 07:59:04 +02:00
Daniel Schwabeneder ff751ca423 implement showaxis and basic framestyles for pgfplots 2017-10-01 20:29:46 +02:00
Daniel Schwabeneder 93df7f4367 implement showaxis for glvisualize 2017-10-01 19:09:24 +02:00
Josef Heinen dca5a7ce4d Merge pull request #1119 from apalugniok/master
Change GR default 3D view angles
2017-10-01 12:50:51 +02:00
apalugniok bf4dd78a7d Change GR default 3D view angles to match PyPlot 2017-10-01 10:29:44 +01:00
Jan Weidner 489e484117 bump required RecipesBase to 0.2.3 2017-09-29 23:24:58 +02:00
Jan Weidner 6e1cc8449b replace d by plotattributes inside recipes 2017-09-29 23:09:34 +02:00
Daniel Schwabeneder 148ad8032f implement showaxis for pyplot 2017-09-29 20:16:27 +02:00
Daniel Schwabeneder 6d53594850 implement showaxis for plotly 2017-09-29 15:09:28 +02:00
Daniel Schwabeneder ee7a3b3686 general axis fixes and improvemennts 2017-09-29 13:41:54 +02:00
Daniel Schwabeneder 18188516ec implement showaxis attribute for gr 2017-09-29 11:48:17 +02:00
Michael Krabbe Borregaard bcc2f089be Merge pull request #1115 from mkborregaard/default-function-limits
Function default x limits: fix #1109
2017-09-29 09:44:54 +02:00
Michael K. Borregaard 07843c00d3 Add negative ranges 2017-09-29 09:18:20 +02:00
Daniel Schwabeneder de12915eba Merge pull request #1112 from daschw/tick-orientation
Implement new tick_direction attribute for GR, Plotly(JS), PyPlot, GLVisualize and PGFPlots
2017-09-29 09:08:52 +02:00
Michael K. Borregaard 4395718e0c Try to find default x axis limits where function is defined 2017-09-29 08:58:54 +02:00
Michael Krabbe Borregaard 913fdf5247 Merge pull request #1114 from mkborregaard/fix-1113
Don't delete attr when `plot(::Plot)` - fix #1113
2017-09-29 08:34:44 +02:00
Michael K. Borregaard 650c1730c9 Don't delete attr when plot(::Plot) - fix #1113 2017-09-28 23:32:25 +02:00
Daniel Schwabeneder fba1c66499 Merge pull request #1110 from daschw/line_z
RFC: Implement line_z and fill_z for GR
2017-09-28 00:12:12 +02:00
Daniel Schwabeneder 1c04823877 reset tick size for gr and glvisualize 2017-09-28 00:07:58 +02:00
Daniel Schwabeneder 6c84624d71 fix pgfplots 2017-09-27 23:22:55 +02:00
Daniel Schwabeneder 69fa9e7b10 implement tick_direction for PGFPlots 2017-09-27 17:07:09 +02:00
Daniel Schwabeneder 350237a774 add tick_direction to supported arguments 2017-09-27 13:56:12 +02:00
Daniel Schwabeneder b73ea55bbd implement tick_direction for GR, PyPlot, Plotly and GLVisualize 2017-09-27 13:53:06 +02:00
Daniel Schwabeneder 9eac6a1db0 fix fillalpha 2017-09-26 17:40:54 +02:00
Daniel Schwabeneder ea6ab46a13 fix fill_z for shapes (draw colorbar once) 2017-09-26 17:18:35 +02:00
Daniel Schwabeneder 5f84865365 implement fill_z and line_z for GR 2017-09-26 16:58:46 +02:00
AnkurD 5b3c41bd77 Colorbar takes font style from Y Axis 2017-09-26 17:22:17 +09:00
AnkurD c6b7ff6c75 Colorbar takes font style from Y Axis 2017-09-26 17:16:03 +09:00
Daniel Schwabeneder 337a107168 different colors for different line segments in GR 2017-09-25 17:22:13 +02:00
Daniel Schwabeneder a7485cc7f5 Merge pull request #1105 from daschw/plot-empty-any
Allow plotting empty Vector{Any} (fix #1078)
2017-09-25 09:57:23 +02:00
Daniel Schwabeneder 8b4edae358 implement line_z for GR 2017-09-24 20:52:02 +02:00
Daniel Schwabeneder b6dca5e9b1 Allow plotting empty Vector{Any} 2017-09-22 20:27:16 +02:00
Daniel Schwabeneder 371f0a6a73 Merge pull request #1092 from daschw/plotly-marker_z
fix marker_z for plotly
2017-09-21 22:04:16 +02:00
Michael Krabbe Borregaard b777a2d3c8 Merge pull request #1096 from fedxa/fix_logscale
Fix for wrong setting of logscale for values below 1e-16
2017-09-20 07:46:16 +02:00
Fedor Bezrukov bdfc4636f0 Fix for wrong setting of logscale for values below 1e-16 2017-09-19 23:22:36 +01:00
Daniel Schwabeneder 7ba128db71 fix marker_z for plotly 2017-09-17 19:14:44 +02:00
Daniel Schwabeneder 0f1d8478ce Merge pull request #1089 from daschw/pyplot-colorbar
activate clims for inactive colorbar in pyplot
2017-09-15 20:04:57 +02:00
Daniel Schwabeneder 9eae2ad76b remove unnecessary setting of needs_colorbar 2017-09-15 18:42:38 +02:00
Daniel Schwabeneder f43f2956f5 activate clims for inactive colorbar 2017-09-15 18:39:56 +02:00
Daniel Schwabeneder 2dc03cc537 Merge pull request #1084 from daschw/pyplot-marker_z
Only one colorbar per subplot on pyplot
2017-09-13 09:17:36 +02:00
Michael Krabbe Borregaard 233b0d0de2 Merge pull request #1086 from anriseth/writemimefix
Use show instead of writemime for eps
2017-09-13 00:09:14 +02:00
Asbjørn Nilsen Riseth dc9a044141 Use show instead of writemime for eps 2017-09-12 16:08:32 +01:00
Daniel Schwabeneder 518fba759f only one colorbar per subplot in pyplot 2017-09-09 11:21:39 +02:00
Daniel Schwabeneder 7dfa1ec984 make GR use hascolorbar 2017-09-09 10:05:58 +02:00
Daniel Schwabeneder da5a538f89 Merge pull request #1083 from daschw/gr-marker_z
Fix GR marker_z and clims (fix #1063)
2017-09-09 09:36:06 +02:00
Daniel Schwabeneder a518796736 reset runtests accuracy 2017-09-08 23:38:43 +02:00
Daniel Schwabeneder 13111b3779 fix marker_z for GR 2017-09-08 22:50:25 +02:00
Michael Krabbe Borregaard 8412d77067 Merge pull request #1082 from timholy/teh/nbins
histogram: ensure the number of bins is finite
2017-09-08 10:25:23 +02:00
Tim Holy fe0ea168f3 histogram: ensure the number of bins is finite 2017-09-08 03:18:46 -05:00
Daniel Schwabeneder af9d97d561 Merge pull request #1077 from daschw/seriestype-error
improve recipe error
2017-09-07 13:29:09 +02:00
Daniel Schwabeneder 478f5b6e20 Merge pull request #1079 from daschw/framestyle
implement framestyles for plotly(js) (fix #1075)
2017-09-07 13:28:43 +02:00
Daniel Schwabeneder c89b125b9a implement framestyles for plotly(js) 2017-09-06 19:09:52 +02:00
Daniel Schwabeneder a981dc71f9 Merge pull request #1057 from daschw/framestyle
RFC: Add :origin framestyle
2017-09-06 16:34:31 +02:00
Daniel Schwabeneder 331dd49326 improve recipe error 2017-09-06 16:03:39 +02:00
Michael Krabbe Borregaard b69c37f1bb Merge pull request #1073 from mkborregaard/fix-2dhistogram-bins
fix 2dhistogram bins
2017-09-06 10:15:03 +02:00
Michael K. Borregaard 20ef846c38 move bracket in Sturges 2017-09-05 22:42:05 +02:00
Michael K. Borregaard cd9f00300c Add correction for correlations 2017-09-05 16:02:52 +02:00
Michael K. Borregaard d6e5b57a08 fix-2dhistogram-bins 2017-09-05 14:01:59 +02:00
Pietro Vertechi d5e5d81ee2 Merge pull request #1062 from piever/groupedbar
WIP: allow to group user recipes
2017-09-05 08:53:26 +01:00
Pietro Vertechi dee24e6f08 add kw support 2017-09-04 12:29:10 +01:00
Michael K. Borregaard 9a2a54b885 reactivate precompilation on master 2017-09-04 13:09:37 +02:00
Michael K. Borregaard 4c2b01ccb0 change version number for testing 2017-09-04 12:18:10 +02:00
Michael Krabbe Borregaard ddf4136022 Merge pull request #1070 from JuliaPlots/release-0.12.4
Release 0.12.4
2017-09-04 12:05:07 +02:00
Michael K. Borregaard 4f8fc61689 Turn off precompile for release 2017-09-04 12:02:34 +02:00
Michael K. Borregaard c8a7a050de Update News.md with 12.4 improvements 2017-09-04 12:02:19 +02:00
Michael Krabbe Borregaard fb04b3d78b Merge pull request #1069 from daschw/seriestype-error
Seriestype error (fix #1068)
2017-09-04 11:50:17 +02:00
Pietro Vertechi 0f28b59c5f added support for 1 or 3 arguments to group as matrix 2017-09-04 10:24:43 +01:00
Pietro Vertechi e2795341d9 moved group_as_matrix to Plots 2017-09-04 09:48:49 +01:00
Michael Krabbe Borregaard 04c20b84ad Merge pull request #1053 from mkborregaard/wand_edges
Make wand edges possible in statplots
2017-09-03 17:30:17 +02:00
Michael Krabbe Borregaard 04f5d7e411 Merge pull request #1064 from mkborregaard/fix-barwidth
Change default bar width to 0.8
2017-09-03 17:28:47 +02:00
Michael Krabbe Borregaard 82877dc53e Merge pull request #1009 from JackDevine/add-stride
Add stride to wireframe/surface
2017-09-03 07:35:35 +02:00
Jack Devine c7eb22021f Merge branch 'master' into add-stride 2017-09-03 13:04:32 +12:00
JackDevine 654fa0426b Remove documentation 2017-09-03 12:53:49 +12:00
Daniel Schwabeneder ae6c1c0c66 make it even more descriptive 2017-09-02 23:19:29 +02:00
Daniel Schwabeneder b3f5939689 make seriestype error more descriptive 2017-09-02 22:58:26 +02:00
Josef Heinen 184404beac Merge pull request #1065 from jheinen/master
gr: suppress default output in Juno
2017-09-02 08:03:01 -04:00
Daniel Schwabeneder 456b8258c3 add zerolines framestyle 2017-09-02 02:35:26 +02:00
Michael K. Borregaard a1896d189c Revert ordering 2017-09-01 16:31:13 +02:00
Michael K. Borregaard e47dde9f41 simplify
but creates type instability
2017-09-01 16:26:49 +02:00
Michael K. Borregaard 4be19ba6d8 Make wand edges possible in statplots 2017-09-01 15:53:26 +02:00
Michael Krabbe Borregaard 73a2839e34 Merge pull request #1037 from mkborregaard/hist-description
changes default histogram bins
2017-09-01 13:20:12 +02:00
Michael Krabbe Borregaard 224472c90a Merge pull request #1048 from mkborregaard/fix-margin-example
Reduce margin to 10 px
2017-09-01 10:40:37 +02:00
Michael K. Borregaard d77be82a99 fix classic typo 2017-09-01 10:36:44 +02:00
Josef Heinen 4320c7b9fb gr: suppress default output in Juno 2017-09-01 07:40:39 +02:00
Michael K. Borregaard 2dcf7fb3dd Change default bar width to 0.8 2017-08-31 23:58:07 +02:00
Michael K. Borregaard cd1913c008 Update bins description 2017-08-31 23:20:55 +02:00
Michael K. Borregaard 62694e4a93 Make Freedman-Diaconis the default 2017-08-31 23:19:00 +02:00
Michael K. Borregaard e92fbadc3a Update histogram normalization desc 2017-08-31 23:12:33 +02:00
Michael K. Borregaard 17c10bbe68 Reduce margin to 10 px 2017-08-31 23:01:46 +02:00
Pietro Vertechi 6c548f025e wip groupedbar 2017-08-31 19:34:38 +01:00
Michael Krabbe Borregaard cc15882faf Merge pull request #1058 from mkborregaard/histogram-like
Make it possible for downstream users (e.g. StatPlots) to define that a seriestype is "histogram-like", "line-like" or "surface-like"
2017-08-31 08:39:16 +02:00
Daniel Schwabeneder 3fd745a5df remove 0 tick label 2017-08-30 23:42:57 +02:00
Daniel Schwabeneder 5e968e0aa8 ticks to axes 2017-08-30 22:19:13 +02:00
Michael Krabbe Borregaard 1e3783b4dc Merge pull request #1052 from mkborregaard/fix-appveyor
add nightly and 32-bit to allow-failures in Appveyor
2017-08-30 14:56:46 +02:00
Michael K. Borregaard c355e02a20 add nightly and 32-bit to allow-failures 2017-08-30 14:56:02 +02:00
Josef Heinen e178dca167 Merge pull request #1060 from jheinen/master
gr: suppress default output in CI or Jupyter mode
2017-08-30 04:36:52 -04:00
Josef Heinen 8beee23e21 gr: suppress default output in CI or Jupyter mode
_update_min_padding() is called before the backend is "started".
In GR, this triggers an automatic initialization and starts the
default output driver (X11, Quartz or GDI). This doesn't make
sense in headless testing environments (CI) or when using Plots
in Jupyter notebooks.

These patches correct this behavour - but it's unclear (to me),
why the call of _update_min_padding() can't be postponed.
2017-08-30 09:59:23 +02:00
Michael K. Borregaard a894d377dc add vectors to hold histogram-like seriestypes and friends 2017-08-29 23:34:07 +02:00
Daniel Schwabeneder f41426c85a fix pyplot 2017-08-29 22:04:33 +02:00
Daniel Schwabeneder 41877e362a add origin framestyle 2017-08-29 20:36:59 +02:00
Daniel Schwabeneder de32b02c75 Merge pull request #1056 from jgoldfar/fix-incorrect-escape-v0.7
Fix incorrect escape sequence error on Julia nightly
2017-08-29 19:33:02 +02:00
Jonathan Goldfarb e3cba22ab7 Correct fix to warning for unknown grid argument. 2017-08-29 13:29:30 -04:00
Jonathan Goldfarb 25bcc3cbc1 Fix incorrect escape sequence error on v0.7. 2017-08-29 12:19:01 -04:00
piever ca5310025f Merge pull request #1033 from piever/group
Group now groups kw arguments as well
2017-08-29 17:16:40 +01:00
piever 5b9561c13e Merge pull request #1049 from piever/ticks
To be merged together with PlotUtils #26: accept axis with 4 ticks
2017-08-29 11:56:46 +01:00
Pietro Vertechi d594ac2f00 Accept axis with 4 ticks 2017-08-28 18:16:10 +01:00
Pietro Vertechi 5157089d87 group on a tuple of vectors 2017-08-27 18:56:10 +01:00
Michael Krabbe Borregaard d5b455b1f9 Merge pull request #1046 from mkborregaard/fix-tests-on-mac
Remove hidden files when checking version numbers
2017-08-27 11:12:59 +02:00
Michael K. Borregaard 6cb1ed6c92 Remove hidden files when checking version numbers 2017-08-27 11:10:06 +02:00
piever 3d0d52f82a Merge pull request #1043 from piever/grfixes
readd fill for cross and xcross on GR
2017-08-26 16:35:50 +01:00
Daniel Schwabeneder be04828d35 Merge pull request #1042 from daschw/ds-blackborder
make linecolor default to :auto
2017-08-26 15:58:11 +02:00
Josef Heinen 5f9aa2edc0 Merge pull request #1044 from jheinen/master
gr: defer the calculation of padding constraints
2017-08-26 13:05:30 +02:00
Josef Heinen a5751895f0 gr: update padding constraints before first plot 2017-08-26 06:49:00 -04:00
Josef Heinen 78b0918216 gr: defer the calculation of padding constraints 2017-08-25 13:54:56 -04:00
Pietro Vertechi 5a7ed24078 allow tuples 2017-08-25 17:01:29 +01:00
Pietro Vertechi 509f8f6a95 readd fill for cross and xcross on GR 2017-08-25 16:46:07 +01:00
Daniel Schwabeneder 6f3301e82f make linecolor default to auto 2017-08-25 14:16:53 +02:00
Josef Heinen 80f11ce30b Merge remote-tracking branch 'upstream/master' 2017-08-25 04:14:59 -04:00
Michael Krabbe Borregaard 95a6d24111 Merge pull request #990 from jverzani/patch-1
Update appveyor.yml
2017-08-25 08:51:30 +02:00
Michael Krabbe Borregaard 1fc2c511af Merge pull request #1030 from mkborregaard/pyplot-in-ijulia
Turn off gui for pyplot in ijulia
2017-08-25 08:47:24 +02:00
Josef Heinen 3bcaac7051 t push
Merge remote-tracking branch 'upstream/master'
2017-08-24 23:05:22 -04:00
Josef Heinen 25afd5c0e7 Merge pull request #1039 from jheinen/master
gr: always use NDCs when inquiring text extents
2017-08-25 05:05:13 +02:00
Josef Heinen dbbbeddad0 gr: always use NDCs when inquiring text extents 2017-08-24 22:32:05 -04:00
Josef Heinen c0f274d54b gr: always use NDCs when inquiring text extents 2017-08-24 22:27:04 -04:00
Michael Krabbe Borregaard 7816e078b5 Merge pull request #808 from darwindarak/dd/world-age
Hack around world age issue PyPlot (fix #734)
2017-08-24 22:53:04 +02:00
Daniel Schwabeneder 56bda82529 Merge pull request #1029 from daschw/ds-axes-border
Allow turning on/off the axes border (fix #1025)
2017-08-24 22:38:01 +02:00
Daniel Schwabeneder 54adc34348 fix glvisualize framestyle :none ticks 2017-08-24 22:21:13 +02:00
Darwin Darakananda a4ed700338 Use invokelatest to get around world age issue 2017-08-24 13:12:32 -07:00
Daniel Schwabeneder e2d107a70b add framestyle test example 2017-08-24 21:39:33 +02:00
Josef Heinen 31f080e4f4 Merge pull request #1038 from piever/grmargin
Adjust margin (ticks + margin given by user) with GR ( fix #1028 )
2017-08-24 20:58:41 +02:00
Daniel Schwabeneder 6e4b9af6b1 Merge pull request #780 from daschw/ds-ticks
WIP: Allow specifying the number of ticks by passing an Integer to the ticks attribute
2017-08-24 17:21:37 +02:00
Daniel Schwabeneder d301d2a06b fix ticks = nothing on pyplot, ... 2017-08-24 16:58:43 +02:00
Daniel Schwabeneder 2bbd4cbb17 clean up 2017-08-24 16:26:54 +02:00
Daniel Schwabeneder 5a2d39320f framestyle attribute for gr, pyplot and glvisualize 2017-08-24 16:13:01 +02:00
Pietro Vertechi 91158b1c20 add proper pad for ticks 2017-08-23 18:19:36 +01:00
Pietro Vertechi 06115f25ba factorize tickfont 2017-08-23 17:45:23 +01:00
Pietro Vertechi b3b533db94 fix margin in case there is no label (gr) 2017-08-23 14:10:35 +01:00
Pietro Vertechi e16125cb50 some GR margin fixes 2017-08-23 13:49:33 +01:00
Michael Krabbe Borregaard eb0dbac0c1 Merge pull request #1035 from piever/errorbar
don't draw fill for 1D markers in gr
2017-08-23 10:35:42 +02:00
Michael Krabbe Borregaard eb1d1876d3 Merge pull request #1034 from JuliaPlots/ChrisRackauckas-patch-1
Remove the -pre
2017-08-23 10:34:54 +02:00
Pietro Vertechi f751b1b7ff don't draw fill for 1D markers in gr 2017-08-23 08:40:19 +01:00
Christopher Rackauckas 34f9cfaa02 Remove the -pre
Plots.jl is no longer tested on the prereleases so it shouldn't say that they are supported.
2017-08-23 00:27:33 -07:00
Pietro Vertechi 6dba32bf99 only check kw is at least as long as group 2017-08-21 15:54:47 +01:00
Pietro Vertechi 9529246bfb keywords arguments of same length as series get grouped 2017-08-21 15:33:30 +01:00
Michael K. Borregaard 25774ee4c3 Turn off gui for pyplot in ijulia 2017-08-21 10:19:47 +02:00
Daniel Schwabeneder 1137513236 add aliases :box and :frame 2017-08-21 00:07:44 +02:00
Daniel Schwabeneder c76855698e Merge pull request #1027 from daschw/ds-datetime-ticks
Allow Date and DateTime as ticks (fix: #1026)
2017-08-20 22:51:26 +02:00
Daniel Schwabeneder be8c66adc9 fix polar plots on pyplot 2017-08-20 22:45:30 +02:00
Daniel Schwabeneder be4a374122 allow turning on/off the axes border 2017-08-20 21:55:21 +02:00
Daniel Schwabeneder d76a6d1c38 Allow and as ticks 2017-08-20 15:43:52 +02:00
Michael Krabbe Borregaard 5945196a4f Merge pull request #1023 from piever/pull-request/eea30fa2
RFC: added ribbon to plotly
2017-08-20 15:13:14 +02:00
Pietro Vertechi e164ea4b46 added default transparency to ribbon 2017-08-20 14:06:15 +01:00
Pietro Vertechi db3dca1d73 changed ribbon legend to line 2017-08-20 11:46:21 +01:00
Pietro Vertechi eea30fa253 added ribbon to plotly 2017-08-19 11:34:13 +01:00
Michael Krabbe Borregaard b585a0ef61 Merge pull request #1012 from mkborregaard/more_docstrings
Specified some docstrings
2017-08-18 10:30:02 +02:00
Michael K. Borregaard db82f22320 add the last docstrings 2017-08-18 09:48:36 +02:00
Michael K. Borregaard 66ce38d948 Specified some docstrings 2017-08-18 09:48:36 +02:00
Daniel Schwabeneder e61d435b00 Merge pull request #1020 from daschw/ds-precompile
reactivate precompilation
2017-08-18 00:58:55 +02:00
Daniel Schwabeneder d0a8985800 Merge pull request #1019 from daschw/ds-release
prepare release
2017-08-18 00:55:29 +02:00
Daniel Schwabeneder 4c1c092234 reactivate precompilation 2017-08-18 00:46:02 +02:00
Daniel Schwabeneder f02079dafe Merge pull request #1014 from daschw/ds-tests
import plot! placeholder from RecipesBase
2017-08-18 00:37:14 +02:00
Daniel Schwabeneder 4be0093a8a prepare release 2017-08-18 00:34:15 +02:00
Daniel Schwabeneder 130eb778d3 Merge pull request #1006 from daschw/ds-grid-axis
grid should be axis attribute (fix #675)
2017-08-17 23:57:59 +02:00
Daniel Schwabeneder be177e0f80 Merge pull request #1015 from daschw/ds-marker-z
only flip colorbar for marker_z on gr
2017-08-17 23:45:35 +02:00
Daniel Schwabeneder 42f54b8df9 remove Bools from _allGridArgs 2017-08-17 14:10:04 +02:00
Daniel Schwabeneder 4b60b05f75 update grid defaults and modify grid example 2017-08-17 13:42:54 +02:00
Michael Krabbe Borregaard 6afd0f9f82 Merge pull request #1011 from martinbiel/enforce-plotorder
Enforce plot order in user recipes
2017-08-17 09:10:01 +02:00
Daniel Schwabeneder 8288e85c25 only flip colorbar for marker_z 2017-08-16 22:32:00 +02:00
Daniel Schwabeneder bb2f4ff16b import inplace plot placeholder from RecipesBase 2017-08-16 21:05:05 +02:00
Daniel Schwabeneder 682ba1f764 allow non-boolean args for xgrid function 2017-08-16 19:41:13 +02:00
Daniel Schwabeneder e0c679f5ee magic grid argument 2017-08-16 17:45:32 +02:00
Martin Biel a1d0d028b6 Updated error text in _process_userrecipes, now uses correct variable 2017-08-16 10:16:37 +02:00
JackDevine 7741872578 Comma in the wrong place 2017-08-16 11:20:04 +12:00
JackDevine d1dcd536f5 I forgot a comma 2017-08-16 10:41:19 +12:00
JackDevine 177d380092 Added suggestions
Changed the interface to stride, which is a tuple. Also added aliases and a docstring in arg_desc.
2017-08-16 10:18:26 +12:00
Martin Biel 33a15f1e93 Process user recipes depth-first rather than breadth-first to enforce the plot order given in the recipe 2017-08-15 18:03:57 +02:00
JackDevine ad2eaf7aef Add stride to wireframe/surface
I only have this for PyPlot at the moment, I would be more than happy
to add other backends if people find it useful. Also, if people have
any ideas for aliases, then I would be happy to do that too.
2017-08-15 20:10:02 +12:00
Daniel Schwabeneder 23ae99b97e undo support for foreground_color_grid and foreground_color_axis attributes in plotly(js) 2017-08-11 12:57:11 +02:00
Daniel Schwabeneder 3c37de152d fix testimage 16 error - only add grid segments when ticks are defined 2017-08-10 22:54:45 +02:00
Daniel Schwabeneder 2dd99d053a make it work on all backends 2017-08-10 20:49:03 +02:00
Daniel Schwabeneder c60d66d94a make it work for gr, pyplot and plotly(js) 2017-08-10 17:46:11 +02:00
Daniel Schwabeneder 6b814b8dca initial commit mostly a copy of #695 2017-08-10 16:32:24 +02:00
Josef Heinen 11c71d7a5d Merge pull request #1005 from jheinen/master
gr: use correct gradient labels for scatter plot
2017-08-10 09:47:57 +02:00
Josef Heinen d90b2e6142 gr: use correct gradient labels for scatter plot 2017-08-10 09:31:54 +02:00
Josef Heinen 2ab7f3c767 Merge pull request #1003 from jheinen/master
gr: no longer handle '_' and '^' in text
2017-08-09 11:03:55 +02:00
Josef Heinen a937fa0ef8 gr: no longer handle '_' and '^' in text 2017-08-09 10:46:23 +02:00
Michael Krabbe Borregaard bc36749f6d Merge pull request #1002 from mkborregaard/mkb-precompile
allow precompilation
2017-08-09 08:12:45 +02:00
Michael K. Borregaard 88d1735380 allow precompilation 2017-08-09 08:12:22 +02:00
Michael K. Borregaard 92672ffddf Update news.md 2017-08-09 08:10:04 +02:00
Michael Krabbe Borregaard 2ccfa9b4fa Merge pull request #1001 from mkborregaard/mkb-release
disable precompilation for release
2017-08-09 08:05:45 +02:00
Michael K. Borregaard 1f07be6ae0 disable precompilation for release 2017-08-09 08:05:21 +02:00
Michael Krabbe Borregaard 9a8c7b290f Merge pull request #1000 from mkborregaard/fix-993
Move when output is included
2017-08-09 08:03:41 +02:00
Michael K. Borregaard 2e3bc15d2b Move when output is included 2017-08-08 20:24:17 +02:00
john verzani 9f0117d914 Update README.md
add appveyor badge. (But how does appveyor get run, as it doesn't seem to be current)
2017-08-01 15:48:12 -04:00
Michael Krabbe Borregaard 5e5412887c Merge pull request #989 from mkborregaard/fix-markershape-recipes
RFC: fix markershape in recipes
2017-07-29 08:51:51 +02:00
Josef Heinen b2efd5150b Merge pull request #992 from jheinen/master
gr: improved calculation of bottom margin
2017-07-28 05:37:09 -05:00
Josef Heinen 50ec31a7a3 gr: improved calculation of bottom margin 2017-07-28 12:17:47 +02:00
Daniel Schwabeneder 20bd9d6160 Merge pull request #988 from stevengj/nopywrap
don't use pywrap
2017-07-28 10:11:30 +02:00
john verzani 8c3c07acb7 Update appveyor.yml
remove v0.5 testing from appveyor
2017-07-27 16:56:17 -04:00
john verzani 26a56c3105 Update appveyor.yml
add testing on v0.6 with 32 and 64 bit.
2017-07-27 15:48:52 -04:00
Steven G. Johnson d0070c72fd whoops, forgot to commit these pywrap fixes 2017-07-27 14:15:48 -04:00
Michael K. Borregaard 780f3c49e9 Add test for markershape 2017-07-27 16:37:55 +02:00
Steven G. Johnson 2c191dbdbf don't use pywrap (closes #983) 2017-07-26 16:34:03 -04:00
Daniel Schwabeneder 4b617f96a3 Merge pull request #987 from daschw/ds-precompile
reactivate precompilation
2017-07-26 15:43:47 +02:00
Daniel Schwabeneder dabc3f998b reactivate precompilation 2017-07-26 15:14:07 +02:00
Daniel Schwabeneder 23a22102c5 Merge pull request #986 from daschw/ds-release
prepare v0.12.1 release
2017-07-26 15:09:33 +02:00
Daniel Schwabeneder 8d9ff7af11 prepare v0.12.1 release 2017-07-26 14:50:57 +02:00
Josef Heinen fdcb6086d1 Merge pull request #985 from jheinen/master
gr: fixed padding for guides
2017-07-26 03:02:03 -05:00
Josef Heinen 00e05efd7c gr: fixed padding for guides 2017-07-26 09:44:34 +02:00
Daniel Schwabeneder 0dd5eef3f2 Merge pull request #982 from daschw/ds-old-matplotlib
Allow Matplotlib 1.5 usage (fix #978)
2017-07-25 18:46:39 +02:00
Daniel Schwabeneder 6ecd30d42b warning --> warn 2017-07-24 14:55:28 +02:00
Daniel Schwabeneder 317091639f Merge pull request #977 from daschw/ds-plotly-surf
allow setting surface alpha in plotly(js) (fix #957)
2017-07-24 10:05:24 +02:00
Daniel Schwabeneder 9c8e879465 Merge pull request #976 from daschw/ds-gr-legend
Line legend marker for ribbons in GR (fix #896)
2017-07-24 10:03:57 +02:00
Daniel Schwabeneder dc5a04346a Merge pull request #975 from daschw/ds-tests
drop FactCheck in tests (fix #915)
2017-07-24 10:03:25 +02:00
Daniel Schwabeneder 44b533f501 allow matplotlib 1.5 usage 2017-07-24 10:02:44 +02:00
Daniel Schwabeneder 0fa459d590 fix alpha in legend markers 2017-07-21 10:52:36 +02:00
Daniel Schwabeneder 96d34bb5ee changed marker for path with fillrange 2017-07-21 10:05:27 +02:00
Daniel Schwabeneder 9f712b44f3 add ribbon area to marker 2017-07-21 09:12:27 +02:00
Daniel Schwabeneder 1ff8663e44 allow setting surface alpha in plotly 2017-07-21 01:12:39 +02:00
Daniel Schwabeneder 52f042263b fix case 2017-07-20 23:38:16 +02:00
Daniel Schwabeneder da7e57989c drop FactCheck and Glob in test/REQUIRE 2017-07-20 22:55:05 +02:00
Daniel Schwabeneder 65c3d90642 Merge pull request #971 from timholy/pull-request/a7a447a8
Update to newer Images
2017-07-20 22:23:52 +02:00
Daniel Schwabeneder 3c044d729d Merge pull request #970 from JuliaPlots/sd/glvisualize
fix glvisualize backend for 0.6
2017-07-20 22:20:34 +02:00
Daniel Schwabeneder 82ecf894c0 fix issues - replace at-fact with at-test 2017-07-20 21:50:06 +02:00
Daniel Schwabeneder 7b15f7d74b fix round() deprecation in gr.jl 2017-07-20 16:08:45 +02:00
Daniel Schwabeneder 371406845c drop Glob (enable testing on Windows) 2017-07-20 13:43:58 +02:00
Daniel Schwabeneder ccd26a6d42 drop FactCheck in tests 2017-07-20 13:25:09 +02:00
SimonDanisch e992930ff6 add contour as a dependency 2017-07-20 10:38:06 +02:00
SimonDanisch f66d8bed8f fix glvisualize backend for 0.6 2017-07-20 10:37:48 +02:00
Daniel Schwabeneder 155634ef34 change gr legend marker for ribbon 2017-07-19 21:26:25 +02:00
Josef Heinen dbc7bc4253 Merge pull request #940 from daschw/ds-heatmap-logscale
Avoid non-positive heatmap edges for log axis on GR and PyPlot
2017-07-18 01:22:26 -05:00
Daniel Schwabeneder fc427e618a Merge pull request #916 from pfitzseb/sp/juno
WIP: Better Juno integration
2017-07-17 20:40:48 +02:00
Sebastian Pfitzner 6d66190644 no eval shenanigans 2017-07-17 15:16:20 +02:00
Daniel Schwabeneder 9b2da0d645 Merge branch 'master' into ds-heatmap-logscale 2017-07-16 12:51:33 +02:00
Sebastian Pfitzner 95c60b9554 unrecursify this definition 2017-07-15 12:01:00 +02:00
Sebastian Pfitzner bc7f6a6fac circumvent warnings 2017-07-15 11:40:11 +02:00
Daniel Schwabeneder 0b1118540a Merge pull request #969 from pearlzli/plotly-fill
Add fillrange for Plotly backend
2017-07-14 22:55:33 +02:00
Tim Holy 96bd0bb46c Fix some errors/depwarns 2017-07-14 10:09:30 -05:00
Tim Holy 33e97ee49b Update to newer Images 2017-07-14 10:07:58 -05:00
Daniel Schwabeneder 8414facde2 Merge pull request #967 from JackDevine/fix-pyplot-deprecation
Fixed a deprecation warning on the pyplot backend
2017-07-13 09:33:25 +02:00
Pearl Li 2a0d5a0a03 Hide legend entry for series being filled to 2017-07-12 17:04:19 -04:00
Pearl Li aec30301a1 Add fillrange for Plotly 2017-07-12 16:20:53 -04:00
Sebastian Pfitzner 9cf246a03e fix juno plot sizing fallback 2017-07-12 10:40:26 +02:00
Sebastian Pfitzner c385035ac5 handle ijulia with requires
and properly check if juno/ijulia are actually used and not just loaded
2017-07-12 10:38:15 +02:00
JackDevine 409cf2c630 Fixed a deprecation warning on the pyplot backend
The follwing code created a deprecation warining:
using Plots; pyplot()
plot([1,2,3,4], [2,3,4,5], yscale=:log10)
2017-07-12 17:37:37 +12:00
SimonDanisch 02ddbc8381 fix glvisualize backend for 0.6 2017-07-11 09:04:35 +02:00
Daniel Schwabeneder 1c2a588864 Merge pull request #965 from rdeits/staticarrays
Switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
2017-07-10 13:47:49 +02:00
Robin Deits de043eeaa2 switch from FixedSizeArrays to StaticArrays.FixedSizeArrays 2017-07-05 17:12:39 -04:00
Sebastian Pfitzner 5e5f23b5e5 fix world age error 2017-07-02 20:56:04 +02:00
Sebastian Pfitzner d671ccd6ba better juno integration 2017-07-02 20:56:04 +02:00
Daniel Schwabeneder f4f2f09d17 Merge pull request #955 from albi3ro/master
fixing deprecation warning
2017-06-28 21:04:04 +02:00
Christina Lee 2f1c70e49f fixing deprecation warning 2017-06-28 11:42:16 -07:00
Josef Heinen d9890498d1 Merge pull request #951 from jheinen/master
gr: implemented "old" heatmap behaviour
2017-06-23 00:52:04 +02:00
Josef Heinen 46ae505bab gr: implemented "old" heatmap behaviour 2017-06-22 15:31:13 -07:00
Josef Heinen b0e84a68d0 Merge pull request #949 from jheinen/master
gr: fixed heatmap bug
2017-06-22 21:58:37 +02:00
Josef Heinen 356a5b6136 gr: fixed heatmap bug 2017-06-22 12:56:41 -07:00
Daniel Schwabeneder e86193cebe Merge pull request #947 from daschw/ds-datetime
Replace deprecated DateTime convert methods
2017-06-22 20:51:50 +02:00
Daniel Schwabeneder e35b2ec3ff replace deprecated DateTime convert methods 2017-06-22 18:51:03 +02:00
Josef Heinen 69d421d785 Merge pull request #944 from jheinen/master
gr: heatmaps now respect xlim/ylim specifications
2017-06-20 03:34:04 +02:00
Josef Heinen 47c51b28c1 gr: heatmaps now respect xlim/ylim specifications
Fixes https://github.com/JuliaPlots/Plots.jl/issues/942
2017-06-19 18:15:33 -07:00
Daniel Schwabeneder dd2653968e Merge pull request #941 from daschw/ds-plotlyjs-colorbar
Allow turning off the colorbar for heatmap, contour and surface on Plotly and PlotlyJS (fix #932)
2017-06-19 20:04:22 +02:00
Daniel Schwabeneder b091d95eb2 turn off colorbar for wireframe 2017-06-18 17:56:47 +02:00
Daniel Schwabeneder 33327d3992 allow turning off the colorbar for heatmap, contour and surface 2017-06-18 17:45:20 +02:00
Daniel Schwabeneder 027ce58655 avoid negative heatmap edges for log axis on gr and pyplot 2017-06-18 16:14:44 +02:00
Daniel Schwabeneder cd611ef4bf Merge pull request #939 from daschw/ds-tests
changed wkhtmltox link for tests
2017-06-18 16:10:25 +02:00
Daniel Schwabeneder bc7f5118ea changed package name for dpkg 2017-06-18 15:51:24 +02:00
Daniel Schwabeneder 53ae915044 changed wkhtmltox link 2017-06-18 11:59:27 +02:00
Michael Krabbe Borregaard a47f14ec13 Merge pull request #936 from ma-laforge/inspectdr
Conform to changes in InspectDR.PlotLayout.
2017-06-18 08:00:09 +02:00
MA Laforge 86149ba3a7 Conform to changes in InspectDR.PlotLayout. 2017-06-16 17:17:01 -04:00
Michael Krabbe Borregaard cc3822b222 Merge pull request #933 from sbromberger/patch-1
Update output.jl
2017-06-16 17:21:26 +02:00
Seth Bromberger 57b9602b13 Update output.jl
Change `readall` to `readstring` for 0.6- compatibility.
2017-06-15 20:12:26 -07:00
Daniel Schwabeneder c9839dbefa Merge pull request #926 from daschw/ds-pyplot-colorbar
Reduced colorbar size on PyPlot for big z values (fix #925)
2017-06-13 18:48:48 +02:00
Daniel Schwabeneder 5b6423ec6c only change top corners of colorbar axes 2017-06-12 22:15:57 +02:00
Daniel Schwabeneder b3efcf9b68 reduced colorbar size for z axis limits >= 1e7 2017-06-12 20:39:49 +02:00
Michael Krabbe Borregaard cadb0f96e2 Merge pull request #837 from floswald/reset
resetfontsizes: fixes #836
2017-06-12 13:31:55 +02:00
florian oswald d3b825b49f fix docstrings. provide 2 methods scalefontsizes now, with and without an argument. no argument version resets to initial values, with argument you rescale the current sizes. 2017-06-12 12:29:19 +02:00
Michael K. Borregaard c808cbb4fa restore precompilation 2017-06-11 22:28:07 +02:00
Daniel Schwabeneder dd526e00ab undo: fix passing ticks tuple on 0.6 2017-05-21 23:47:26 +02:00
Daniel Schwabeneder bad2ef63c6 fix passing ticks tuple on 0.6 2017-05-21 23:44:12 +02:00
florian oswald 6cca763284 removed test for k 2017-05-17 21:07:54 +02:00
Florian Oswald 915c41c9d9 addressed changes requested 2017-05-17 17:48:03 +02:00
Florian Oswald 9c2c548874 create dict _initial_fontsizes and copy from that. creates new method scalefontsizes() [no keyword] 2017-05-17 17:10:21 +02:00
Florian Oswald fdf699bf35 added const copies of _all_defaults and _axis_defaults to be able to reset fonts to initial values with new resetfontsizes method 2017-05-17 16:34:03 +02:00
Florian Oswald e3ce1ab1d1 just calling default(k) does not give back the default value for k 2017-05-17 15:40:47 +02:00
Florian Oswald af56d6f265 added resetfontsizes() 2017-05-17 15:31:26 +02:00
Daniel Schwabeneder 93d16a27c1 undo unnecessary changes 2017-04-30 19:27:01 +02:00
Daniel Schwabeneder a602309a02 wip let axis limits expand 2017-04-30 19:02:42 +02:00
Daniel Schwabeneder 11e9eb3aa3 allow Int as input type for the ticks attribute to set the desired number of ticks 2017-04-23 20:30:48 +02:00
51 changed files with 4837 additions and 2150 deletions
+6 -5
View File
@@ -4,10 +4,11 @@ os:
- linux
# - osx
julia:
- 0.6
matrix:
allow_failures:
- julia: nightly
# - 0.7
- nightly
# matrix:
# allow_failures:
# - julia: nightly
# # before install:
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
@@ -44,7 +45,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")'
+217 -4
View File
@@ -3,14 +3,227 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.12!
- 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.4
- `backports` branch is for Julia 0.5
---
## (current master)
- All new development should target Julia 1.x!
## 0.12 (current master/dev)
## 0.19.2
- several small fixes for 1.0 compatibility
## 0.19.1
- don't broadcast plot_color
## 0.19.0
- Refactor conditional loading to use Requires
- Many fixes for 1.0 compatibility
## 0.18.0
- update minor version to 0.7
## 0.17.4
- fix thickness_scaling for pyplot
## 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
- Improve histogram2d bin estimation
- Allow vector arguments for certain series attributes and support line_z and fill_z on GR, PyPlot, Plotly(JS) and PGFPlots
- Automatic scientific notation for tick labels
- Allow to set the theme in PLOTS_DEFAULTS
- Implement plots_heatmap seriestype providing a Plots recipe for heatmaps
## 0.16.0
- fix 3D plotting in PyPlot
- Infinite objects
## 0.15.1
- fix scientific notation for labels in GR
- fix labels with logscale
- fix image cropping with GR
- fix grouping of annotations
- fix annotations in Plotly
- allow saving notebook with plots as pdf from IJulia
- fix fillrange and ribbon for step recipes
- implement native ticks that respond to zoom
- fix bar plot with one bar
- contour labels and colorbar fixes
- interactive linked axis for PyPlot
- add `NamedTuple` syntax to group with named legend
- use bar recipe in Plotly
- implement categorical ticks
## 0.15.0
- improve resolution of png output of GR with savefig()
- add check for ticks=nothing
- allow transparency in heatmaps
- fix line_z for GR
- fix legendcolor for pyplot
- fix pyplot ignoring alpha values of images
- don't let `abline!` change subplot limits
- update showtheme recipe
## 0.14.2
- fix plotly bar lines bug
- allow passing multiple series to `ribbon`
- add a new example for `line_z`
## 0.14.1
- Add linestyle argument to the legend
- Plotly: bar_width and stroke_width support for bar plots
- abline! does not change axis limits
- Fix default log scale ticks in GR backend
- Use the :fontsize keys so the scalefontsizes command works
- Prepare support for new PlotTheme type in PlotThemes
## 0.14.0
- remove use of imagemagick; saving gifs now requires ffmpeg
- improvements to ffmpeg gif quality and speed
- overhaul of fonts, allows setting fonts in recipes and with magic arguments
- added `camera` attribute to control camera position for 3d plots
- added `showaxis` attribute to control which axes to display
- improvements of polar plots axes, and better backend consistency
- changed the 'spy' recipe back to using heatmap
- added `scatterpath` seriestype
- allow plotlyjs to save svg
- add `reset_defaults()` function to reset plot defaults
- update syntax to 0.6
- make `fill = true` fill to 0 rather than to 1
- use new `@df` syntax in StatPlots examples
- allow changing the color of legend box
- implement `title_location` for gr
- add `hline` marker to pgfplots - fixes errorbars
- pyplot legends now show marker types
- pyplot colorbars take font style from y axis
- pyplot tickmarks color the same as axis color
- allow setting linewidth for contour in gr
- allow legend to be outside plot area for pgfplots
- expand axis extrema for heatmap
- extendg grid lines to axis limits
- fix `line_z` for pyplot and gr
- fixed colorbar problem for flipped axes with gr
- fix marker_z for 3d plots in gr
- fix `weights` functionality for histograms
- fix gr annotations with colorbar
- fix aspect ratio in gr
- fix "hidden window" problem after savefig in gr
- fix pgfplots logscale ticks error
- fix pgfplots legends symbols
- fix axis linking for plotlyjs
- fix plotting of grayscale images
## 0.13.1
- fix a bug when passing a vector of functions with no bounds (e.g. `plot([sin, cos])`)
- export `pct` and `px` from Plots.PlotMeasures
## 0.13.0
- support `plotattributes` rather than `d` in recipes
- no longer export `w`, `h` and names from Measures.jl; use `using Plots.PlotMeasures` to get these names back
- `bar_width` now depends on the minimum distance between bars, not the mean
- better automatic x axis limits for plotting Functions
- `tick_direction` attribute now allows ticks to be on the inside of the plot border
- removed a bug where `p1 = plot(randn(10)); plot(p1, p2)` made `display(p1)` impossible
- allow `plot([])` to generate an empty plot
- add `origin` framestyle
- ensure finite bin number on histograms with only one unique value
- better automatic histogram bins for 2d histograms
- more informative error message on passing unsupported seriestype in a recipe
- allow grouping in user recipes
- GR now has `line_z` and `fill_z` attributes for determining the color of shapes and lines
- change GR default view angle for 3D plots to match that of PyPlot
- fix `clims` on GR
- fix `marker_z` for plotly backend
- implement `framestyle` for plotly
- fix logscale bug error for values < 1e-16 on pyplot
- fix an issue on pyplot where >1 colorbar would be shown if there was >1 series
- fix `writemime` for eps
## 0.12.4
- added a new `framestyle` argument with choices: :box, :semi, :axes, :grid and :none
- changed the default bar width to 0.8
- added working ribbon to plotly backend
- ensure that automatic ticks always generate 4 to 8 ticks
- group now groups keyword arguments of the same length as the input
- allow passing DateTime objects as ticks
- allow specifying the number of ticks as an integre
- fix bug on errorbars in gr
- fixed some but not all world age issues
- better margin with room for text
- added a `match` option for linecolor
- better error message un unsupported series types
- add a 'stride' keyword for the pyplot backend
## 0.12.3
- new grid line style defaults
- `grid` is now an axis attribute and a magic argument: it is now possible to modify the grid line style, alpha and line width
- Enforce plot order in user recipes
- import `plot!` from RecipesBase
- GR no longer automatically handles _ and ^ in texts
- fix GR colorbar for scatter plots
#### 0.12.2
- fix an issue with Juno/PlotlyJS compatibility on new installations
- fix markers not showing up in seriesrecipes using :scatter
- don't use pywrap in the pyplot backend
- improve the bottom margin for the gr backend
#### 0.12.1
- fix deprecation warnings
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
- drop FactCheck in tests
- remove julia 0.5 compliant uses of transpose operator
- fix GR heatmap bugs
- fix GR guide padding
- improve legend markers in GR
- add surface alpha for Plotly(JS)
- add fillrange to Plotly(JS)
- allow usage of Matplotlib 1.5 with PyPlot
- fix GLVisualize for julia 0.6
- conform to changes in InspectDR
#### 0.12.0
- 0.6 only
@@ -29,7 +242,7 @@
#### 0.11.0
- julia 0.6 compatibility
- matplotlib 0.2.0 compatibility
- matplotlib 2.0 compatibility
- add inspectdr backend
- improved histogram functionality:
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)
+5 -2
View File
@@ -1,13 +1,16 @@
# Plots
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/mkborregaard/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
<!-- [![Coverage Status](https://coveralls.io/repos/tbreloff/Plots.jl/badge.svg?branch=master)](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
<!-- [![codecov.io](http://codecov.io/github/tbreloff/Plots.jl/coverage.svg?branch=master)](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
#### Author: Thomas Breloff (@tbreloff)
#### Created by Tom Breloff (@tbreloff)
#### Maintained by the [JuliaPlot members](https://github.com/orgs/JuliaPlots/people)
Plots is a plotting API and toolset. My goals with the package are:
@@ -19,4 +22,4 @@ Plots is a plotting API and toolset. My goals with the package are:
- **Lightweight**. Very few dependencies.
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
View the [full documentation](http://juliaplots.github.io).
View the [full documentation](http://docs.juliaplots.org/latest).
+6 -3
View File
@@ -1,13 +1,16 @@
julia 0.6-pre
julia 0.7
RecipesBase 0.2.0
RecipesBase 0.2.3
PlotUtils 0.4.1
PlotThemes 0.1.3
Reexport
FixedSizeArrays
StaticArrays 0.5
FixedPointNumbers 0.3
Measures
Showoff
StatsBase 0.14.0
JSON
NaNMath
Requires
Contour
GR 0.31.0
+7 -2
View File
@@ -1,10 +1,15 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
# matrix:
# allow_failures:
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
notifications:
- provider: Email
on_build_success: false
+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
+103 -48
View File
@@ -1,16 +1,22 @@
__precompile__(false)
module Plots
using Reexport
using FixedSizeArrays
import StaticArrays
using StaticArrays.FixedSizeArrays
using Dates, Printf, Statistics, Base64, LinearAlgebra
import SparseArrays: findnz
@reexport using RecipesBase
import RecipesBase: plot, animate
import RecipesBase: plot, plot!, animate
using Base.Meta
@reexport using PlotUtils
@reexport using PlotThemes
import Showoff
import StatsBase
import JSON
using Requires
export
grid,
@@ -49,6 +55,8 @@ export
yflip!,
xaxis!,
yaxis!,
xgrid!,
ygrid!,
xlims,
ylims,
@@ -105,13 +113,13 @@ export
# ---------------------------------------------------------
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
ignorenan_minimum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.minimum(x)
ignorenan_minimum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.minimum(x)
ignorenan_minimum(x) = Base.minimum(x)
ignorenan_maximum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.maximum(x)
ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
ignorenan_maximum(x) = Base.maximum(x)
ignorenan_mean{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.mean(x)
ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
ignorenan_mean(x) = Base.mean(x)
ignorenan_extrema{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.extrema(x)
ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
ignorenan_extrema(x) = Base.extrema(x)
# ---------------------------------------------------------
@@ -128,11 +136,20 @@ ignorenan_extrema(x) = Base.extrema(x)
# ---------------------------------------------------------
import Measures
module PlotMeasures
import Measures
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
const BBox = Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h
end
using .PlotMeasures
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
# ---------------------------------------------------------
include("types.jl")
@@ -148,12 +165,12 @@ include("layouts.jl")
include("subplots.jl")
include("recipes.jl")
include("animation.jl")
include("output.jl")
include("examples.jl")
include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
include("output.jl")
include("init.jl")
# ---------------------------------------------------------
@@ -167,10 +184,13 @@ include("backends.jl")
@shorthands histogram2d
@shorthands density
@shorthands heatmap
@shorthands plots_heatmap
@shorthands hexbin
@shorthands sticks
@shorthands hline
@shorthands vline
@shorthands hspan
@shorthands vspan
@shorthands ohlc
@shorthands contour
@shorthands contourf
@@ -184,56 +204,90 @@ include("backends.jl")
@shorthands quiver
@shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
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!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = 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!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
yticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
xticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
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 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::TicksArgs; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; 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...)
global yticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), 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
@@ -241,13 +295,14 @@ end
const CURRENT_BACKEND = CurrentBackend(:none)
function __init__()
setup_ijulia()
setup_atom()
# for compatibility with Requires.jl:
@init begin
if isdefined(Main, :PLOTS_DEFAULTS)
if haskey(Main.PLOTS_DEFAULTS, :theme)
theme(Main.PLOTS_DEFAULTS[:theme])
end
for (k,v) in Main.PLOTS_DEFAULTS
default(k, v)
k == :theme || default(k, v)
end
end
end
+36 -36
View File
@@ -1,5 +1,5 @@
immutable Animation
"Represents an animation object"
struct Animation
dir::String
frames::Vector{String}
end
@@ -9,7 +9,12 @@ function Animation()
Animation(tmpdir, String[])
end
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
"""
frame(animation[, plot])
Add a plot (the current plot if not specified) to an existing animation
"""
function frame(anim::Animation, plt::P=current()) where P<:AbstractPlot
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename))
@@ -20,7 +25,7 @@ giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
type FrameIterator
mutable struct FrameIterator
itr
every::Int
kw
@@ -49,47 +54,40 @@ end
# -----------------------------------------------
"Wraps the location of an animated gif so that it can be displayed"
immutable AnimatedGif
struct AnimatedGif
filename::String
end
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...)
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn; kw...)
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
const _imagemagick_initialized = Ref(false)
function buildanimation(animdir::AbstractString, fn::AbstractString;
fps::Integer = 20, loop::Integer = 0)
function buildanimation(animdir::AbstractString, fn::AbstractString,
is_animated_gif::Bool=true;
fps::Integer = 20, loop::Integer = 0,
variable_palette::Bool=false,
show_msg::Bool=true)
fn = abspath(fn)
try
if !_imagemagick_initialized[]
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
include(file)
end
_imagemagick_initialized[] = true
if is_animated_gif
if variable_palette
# generate a colorpalette for each frame for highest quality, but larger filesize
palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`)
else
# generate a colorpalette first so ffmpeg does not have to guess it
run(`ffmpeg -v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
# then apply the palette to get better results
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`)
end
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
# high quality
speed = round(Int, 100 / fps)
run(`convert -delay $speed -loop $loop $(joinpath(animdir, "*.png")) -alpha off $fn`)
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
You may also need to install the imagemagick c++ library through your operating system.
Will try ffmpeg, but it's lower quality...)""")
# low quality
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -y $fn`)
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
else
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
end
info("Saved animation to ", fn)
show_msg && @info("Saved animation to ", fn)
AnimatedGif(fn)
end
@@ -118,6 +116,7 @@ function _animate(forloop::Expr, args...; callgif = false)
# add the call to frame to the end of each iteration
animsym = gensym("anim")
countersym = gensym("counter")
freqassert = :()
block = forloop.args[2]
# create filter
@@ -130,7 +129,7 @@ function _animate(forloop::Expr, args...; callgif = false)
# filter every `freq` frames (starting with the first frame)
@assert n == 2
freq = args[2]
@assert isa(freq, Integer) && freq > 0
freqassert = :(@assert isa($freq, Integer) && $freq > 0)
:(mod1($countersym, $freq) == 1)
elseif args[1] == :when
@@ -143,15 +142,16 @@ function _animate(forloop::Expr, args...; callgif = false)
end
push!(block.args, :(if $filterexpr; frame($animsym); end))
push!(block.args, :($countersym += 1))
push!(block.args, :(global $countersym += 1))
# add a final call to `gif(anim)`?
retval = callgif ? :(gif($animsym)) : animsym
# full expression:
esc(quote
$freqassert # if filtering, check frequency is an Integer > 0
$animsym = Animation() # init animation object
$countersym = 1 # init iteration counter
global $countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
$retval # return the animation object, or the gif
end)
+46 -10
View File
@@ -21,7 +21,7 @@ const _arg_desc = KW(
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto. For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(min(x), stop = extrema(x), length = 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
@@ -40,9 +40,10 @@ const _arg_desc = KW(
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a PDF with integral of 1) and :density (only normalize in respect to bin sizes).",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:contour_labels => "Bool. Show labels at the contour lines?",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
@@ -64,27 +65,37 @@ 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",
# subplot args
:title => "String. Subplot title.",
:title_location => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefont => "Font. Font of subplot title.",
:titlefontfamily => "String or Symbol. Font family of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center",
:titlefontrotation => "Real. Font rotation of subplot title",
:titlefontcolor => "Color Type. Font color of subplot title",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
:legendtitle => "String or nothing (default). Sets the legend title.",
:legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.",
:grid => "Bool. Show the grid lines?",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
@@ -95,21 +106,46 @@ const _arg_desc = KW(
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args
: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.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
:tickfont => "Font. Font of axis tick labels.",
:guidefont => "Font. Font of axis guide (label).",
:tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center",
:tickfontrotation => "Real. Font rotation of tick labels",
:tickfontcolor => "Color Type. Font color of tick labels",
:guidefontfamily => "String or Symbol. Font family of axes guides.",
:guidefontsize => "Integer. Font pointsize of axes guides.",
:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center",
:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center",
:guidefontrotation => "Real. Font rotation of axes guides",
:guidefontcolor => "Color Type. Font color of axes guides",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
:minorticks => "Integer. Intervals to divide the gap between major ticks into",
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
:minorgridlinewidth => "Number. Width of the minor 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`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
)
+422 -71
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
@@ -80,9 +80,13 @@ const _typeAliases = Dict{Symbol,Symbol}(
add_non_underscore_aliases!(_typeAliases)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins)
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
const _histogram_like = [:histogram, :barhist, :barbins]
const _line_like = [:line, :path, :steppre, :steppost]
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
like_histogram(seriestype::Symbol) = seriestype in _histogram_like
like_line(seriestype::Symbol) = seriestype in _line_like
like_surface(seriestype::Symbol) = seriestype in _surface_like
is3d(seriestype::Symbol) = seriestype in _3dTypes
is3d(series::Series) = is3d(series.d)
@@ -155,14 +159,75 @@ const _markerAliases = Dict{Symbol,Symbol}(
:spike => :vline,
)
const _positionAliases = Dict{Symbol,Symbol}(
:top_left => :topleft,
:tl => :topleft,
:top_center => :topcenter,
:tc => :topcenter,
:top_right => :topright,
:tr => :topright,
:bottom_left => :bottomleft,
:bl => :bottomleft,
:bottom_center => :bottomcenter,
:bc => :bottomcenter,
:bottom_right => :bottomright,
:br => :bottomright,
)
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,
)
const _allGridSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on, :yes, :show,
:none, :off, :no, :hide]
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
hasgrid(arg::Nothing, letter) = false
hasgrid(arg::Bool, letter) = arg
function hasgrid(arg::Symbol, letter)
if arg in _allGridSyms
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
end
end
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allShowaxisSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on, :yes, :show,
:off, :no, :hide]
const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)]
showaxis(arg::Nothing, letter) = false
showaxis(arg::Bool, letter) = arg
function showaxis(arg::Symbol, letter)
if arg in _allGridSyms
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
end
end
showaxis(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
const _framestyleAliases = Dict{Symbol, Symbol}(
:frame => :box,
:border => :box,
:on => :box,
:transparent => :semi,
:semitransparent => :semi,
)
const _bar_width = 0.8
# -----------------------------------------------------------------------------
const _series_defaults = KW(
@@ -172,7 +237,7 @@ const _series_defaults = KW(
:seriestype => :path,
:linestyle => :solid,
:linewidth => :auto,
:linecolor => :match,
:linecolor => :auto,
:linealpha => nothing,
:fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match,
@@ -207,6 +272,7 @@ const _series_defaults = KW(
:normalize => false, # do we want a normalized histogram?
:weights => nothing, # optional weights for histograms (1D and 2D)
:contours => false, # add contours to 3d surface and wireframe plots
:contour_labels => false,
:match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
:subplot => :auto, # which subplot(s) does this series belong to?
@@ -214,6 +280,7 @@ const _series_defaults = KW(
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
# one logical series to be broken up (path and markers, for example)
:hover => nothing, # text to display when hovering over the data points
:stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride.
)
@@ -222,6 +289,7 @@ const _plot_defaults = KW(
:background_color => colorant"white", # default for all backgrounds,
:background_color_outside => :match, # background outside grid,
:foreground_color => :auto, # default for all foregrounds, and title color,
:fontfamily => "sans-serif",
:size => (600,400),
:pos => (0,0),
:window_title => "Plots.jl",
@@ -233,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(),
)
@@ -241,21 +310,30 @@ const _plot_defaults = KW(
const _subplot_defaults = KW(
:title => "",
:title_location => :center, # also :left or :right
:titlefont => font(14),
:fontfamily_subplot => :match,
:titlefontfamily => :match,
:titlefontsize => 14,
:titlefonthalign => :hcenter,
:titlefontvalign => :vcenter,
:titlefontrotation => 0.0,
:titlefontcolor => :match,
:background_color_subplot => :match, # default for other bg colors... match takes plot default
:background_color_legend => :match, # background of legend
:background_color_inside => :match, # background inside grid
:foreground_color_subplot => :match, # default for other fg colors... match takes plot default
:foreground_color_legend => :match, # foreground of legend
:foreground_color_grid => :match, # grid color
:foreground_color_title => :match, # title color
:color_palette => :auto,
:legend => :best,
:legendtitle => nothing,
:colorbar => :legend,
:clims => :auto,
:legendfont => font(8),
:grid => true,
:legendfontfamily => :match,
:legendfontsize => 8,
:legendfonthalign => :hcenter,
:legendfontvalign => :vcenter,
:legendfontrotation => 0.0,
:legendfontcolor => :match,
:annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal
@@ -266,6 +344,8 @@ const _subplot_defaults = KW(
:bottom_margin => :match,
:subplot_index => -1,
:colorbar_title => "",
:framestyle => :axes,
:camera => (30,30),
)
const _axis_defaults = KW(
@@ -276,8 +356,18 @@ const _axis_defaults = KW(
:rotation => 0,
:flip => false,
:link => [],
:tickfont => font(8),
:guidefont => font(11),
:tickfontfamily => :match,
:tickfontsize => 8,
:tickfonthalign => :hcenter,
:tickfontvalign => :vcenter,
:tickfontrotation => 0.0,
:tickfontcolor => :match,
:guidefontfamily => :match,
:guidefontsize => 11,
:guidefonthalign => :hcenter,
:guidefontvalign => :vcenter,
:guidefontrotation => 0.0,
:guidefontcolor => :match,
:foreground_color_axis => :match, # axis border/tick colors,
:foreground_color_border => :match, # plot area border/spines,
:foreground_color_text => :match, # tick text color,
@@ -285,6 +375,20 @@ const _axis_defaults = KW(
:discrete_values => [],
:formatter => :auto,
:mirror => false,
:grid => true,
:foreground_color_grid => :match, # grid color
:gridalpha => 0.1,
:gridstyle => :solid,
:gridlinewidth => 0.5,
:foreground_color_minor_grid => :match, # grid color
:minorgridalpha => 0.05,
:minorgridstyle => :solid,
:minorgridlinewidth => 0.5,
:tick_direction => :in,
:minorticks => false,
:minorgrid => false,
:showaxis => true,
:widen => true,
)
const _suppress_warnings = Set{Symbol}([
@@ -336,6 +440,15 @@ const _all_defaults = KW[
_axis_defaults_byletter
]
const _initial_defaults = deepcopy(_all_defaults)
const _initial_axis_defaults = deepcopy(_axis_defaults)
# to be able to reset font sizes to initial values
const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefontsize],
:legendfontsize => _subplot_defaults[:legendfontsize],
:tickfontsize => _axis_defaults[:tickfontsize],
:guidefontsize => _axis_defaults[:guidefontsize])
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
@@ -391,12 +504,14 @@ add_aliases(:foreground_color_subplot, :fg_subplot, :fgsubplot, :fgcolor_subplot
:foreground_colour_subplot, :fgcolour_subplot, :fg_colour_subplot)
add_aliases(:foreground_color_grid, :fg_grid, :fggrid, :fgcolor_grid, :fg_color_grid, :foreground_grid,
:foreground_colour_grid, :fgcolour_grid, :fg_colour_grid, :gridcolor)
add_aliases(:foreground_color_minor_grid, :fg_minor_grid, :fgminorgrid, :fgcolor_minorgrid, :fg_color_minorgrid, :foreground_minorgrid,
:foreground_colour_minor_grid, :fgcolour_minorgrid, :fg_colour_minor_grid, :minorgridcolor)
add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_color_title, :foreground_title,
:foreground_colour_title, :fgcolour_title, :fg_colour_title, :titlecolor)
add_aliases(:foreground_color_axis, :fg_axis, :fgaxis, :fgcolor_axis, :fg_color_axis, :foreground_axis,
:foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor)
add_aliases(:foreground_color_border, :fg_border, :fgborder, :fgcolor_border, :fg_color_border, :foreground_border,
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor, :border)
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor)
add_aliases(:foreground_color_text, :fg_text, :fgtext, :fgcolor_text, :fg_color_text, :foreground_text,
:foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor)
add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_color_guide, :foreground_guide,
@@ -408,6 +523,7 @@ add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
# series attributes
add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt)
@@ -463,7 +579,15 @@ add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesa
add_aliases(:html_output_format, :format, :fmt, :html_format)
add_aliases(:orientation, :direction, :dir)
add_aliases(:inset_subplots, :inset, :floating)
add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str)
add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw)
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
add_aliases(:minorgridlinewidth, :minorgridwidth, :minorgrid_linewidth, :minorgrid_width, :minorgridlw, :minorgrid_lw)
add_aliases(:minorgridstyle, :minorgrid_style, :minorgridlinestyle, :minorgrid_linestyle, :minorgrid_ls, :minorgridls)
add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border)
add_aliases(:tick_direction, :tickdirection, :tick_dir, :tickdir, :tick_orientation, :tickorientation, :tick_or, :tickor)
add_aliases(:camera, :cam, :viewangle, :view_angle)
add_aliases(:contour_labels, :contourlabels, :clabels, :clabs)
# add all pluralized forms to the _keyAliases dict
for arg in keys(_series_defaults)
@@ -482,7 +606,6 @@ end
`default(; kw...)` will set the current default value for each key/value pair
`default(d, key)` returns the key from d if it exists, otherwise `default(key)`
"""
function default(k::Symbol)
k = get(_keyAliases, k, k)
for defaults in _all_defaults
@@ -512,6 +635,8 @@ function default(k::Symbol, v)
end
function default(; kw...)
kw = KW(kw)
preprocessArgs!(kw)
for (k,v) in kw
default(k, v)
end
@@ -521,7 +646,10 @@ function default(d::KW, k::Symbol)
get(d, k, default(k))
end
function reset_defaults()
foreach(merge!, _all_defaults, _initial_defaults)
merge!(_axis_defaults, _initial_axis_defaults)
end
# -----------------------------------------------------------------------------
@@ -536,6 +664,7 @@ function handleColors!(d::KW, arg, csym::Symbol)
d[csym] = c
end
return true
catch
end
false
end
@@ -575,7 +704,7 @@ function processLineArg(d::KW, arg)
# color
elseif !handleColors!(d, arg, :linecolor)
warn("Skipped line arg $arg.")
@warn("Skipped line arg $arg.")
end
end
@@ -611,7 +740,7 @@ function processMarkerArg(d::KW, arg)
# markercolor
elseif !handleColors!(d, arg, :markercolor)
warn("Skipped marker arg $arg.")
@warn("Skipped marker arg $arg.")
end
end
@@ -624,6 +753,9 @@ function processFillArg(d::KW, arg)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
elseif typeof(arg) <: Bool
d[:fillrange] = arg ? 0 : nothing
# fillrange function
elseif allFunctions(arg)
d[:fillrange] = arg
@@ -632,6 +764,10 @@ function processFillArg(d::KW, arg)
elseif allAlphas(arg)
d[:fillalpha] = arg
# fillrange provided as vector or number
elseif typeof(arg) <: Union{AbstractArray{<:Real}, Real}
d[:fillrange] = arg
elseif !handleColors!(d, arg, :fillcolor)
d[:fillrange] = arg
@@ -640,6 +776,101 @@ function processFillArg(d::KW, arg)
return
end
function processGridArg!(d::KW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
d[Symbol(letter, :grid)] = hasgrid(arg, letter)
elseif allStyles(arg)
d[Symbol(letter, :gridstyle)] = arg
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[Symbol(letter, :gridlinewidth)] = arg.width)
arg.color == nothing || (d[Symbol(letter, :foreground_color_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color))
arg.alpha == nothing || (d[Symbol(letter, :gridalpha)] = arg.alpha)
arg.style == nothing || (d[Symbol(letter, :gridstyle)] = arg.style)
# linealpha
elseif allAlphas(arg)
d[Symbol(letter, :gridalpha)] = arg
# linewidth
elseif allReals(arg)
d[Symbol(letter, :gridlinewidth)] = arg
# color
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
@warn("Skipped grid arg $arg.")
end
end
function processMinorGridArg!(d::KW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
d[Symbol(letter, :minorgrid)] = hasgrid(arg, letter)
elseif allStyles(arg)
d[Symbol(letter, :minorgridstyle)] = arg
d[Symbol(letter, :minorgrid)] = true
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[Symbol(letter, :minorgridlinewidth)] = arg.width)
arg.color == nothing || (d[Symbol(letter, :foreground_color_minor_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color))
arg.alpha == nothing || (d[Symbol(letter, :minorgridalpha)] = arg.alpha)
arg.style == nothing || (d[Symbol(letter, :minorgridstyle)] = arg.style)
d[Symbol(letter, :minorgrid)] = true
# linealpha
elseif allAlphas(arg)
d[Symbol(letter, :minorgridalpha)] = arg
d[Symbol(letter, :minorgrid)] = true
# linewidth
elseif allReals(arg)
d[Symbol(letter, :minorgridlinewidth)] = arg
d[Symbol(letter, :minorgrid)] = true
# color
elseif handleColors!(d, arg, Symbol(letter, :foreground_color_minor_grid))
d[Symbol(letter, :minorgrid)] = true
else
@warn("Skipped grid arg $arg.")
end
end
function processFontArg!(d::KW, fontname::Symbol, arg)
T = typeof(arg)
if T <: Font
d[Symbol(fontname, :family)] = arg.family
d[Symbol(fontname, :size)] = arg.pointsize
d[Symbol(fontname, :halign)] = arg.halign
d[Symbol(fontname, :valign)] = arg.valign
d[Symbol(fontname, :rotation)] = arg.rotation
d[Symbol(fontname, :color)] = arg.color
elseif arg == :center
d[Symbol(fontname, :halign)] = :hcenter
d[Symbol(fontname, :valign)] = :vcenter
elseif arg in (:hcenter, :left, :right)
d[Symbol(fontname, :halign)] = arg
elseif arg in (:vcenter, :top, :bottom)
d[Symbol(fontname, :valign)] = arg
elseif T <: Colorant
d[Symbol(fontname, :color)] = arg
elseif T <: Symbol || T <: AbstractString
try
d[Symbol(fontname, :color)] = parse(Colorant, string(arg))
catch
d[Symbol(fontname, :family)] = string(arg)
end
elseif typeof(arg) <: Integer
d[Symbol(fontname, :size)] = arg
elseif typeof(arg) <: Real
d[Symbol(fontname, :rotation)] = convert(Float64, arg)
else
@warn("Skipped font arg: $arg ($(typeof(arg)))")
end
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
_replace_markershape(shape) = shape
@@ -658,12 +889,13 @@ function preprocessArgs!(d::KW)
replaceAliases!(d, _keyAliases)
# clear all axis stuff
if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
d[:ticks] = nothing
d[:foreground_color_border] = RGBA(0,0,0,0)
d[:grid] = false
delete!(d, :axis)
end
# if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
# d[:ticks] = nothing
# d[:foreground_color_border] = RGBA(0,0,0,0)
# d[:foreground_color_axis] = RGBA(0,0,0,0)
# d[:grid] = false
# delete!(d, :axis)
# end
# for letter in (:x, :y, :z)
# asym = Symbol(letter, :axis)
# if haskey(d, asym) || d[asym] in (:none, nothing, false)
@@ -672,6 +904,13 @@ function preprocessArgs!(d::KW)
# end
# end
# handle axis args common to all axis
args = pop!(d, :axis, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
process_axis_arg!(d, arg, letter)
end
end
# handle axis args
for letter in (:x, :y, :z)
asym = Symbol(letter, :axis)
@@ -683,6 +922,62 @@ function preprocessArgs!(d::KW)
end
end
# handle grid args common to all axes
args = pop!(d, :grid, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processGridArg!(d, arg, letter)
end
end
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :grid)
args = pop!(d, gridsym, ())
for arg in wraptuple(args)
processGridArg!(d, arg, letter)
end
end
# handle minor grid args common to all axes
args = pop!(d, :minorgrid, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processMinorGridArg!(d, arg, letter)
end
end
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :minorgrid)
args = pop!(d, gridsym, ())
for arg in wraptuple(args)
processMinorGridArg!(d, arg, letter)
end
end
# fonts
for fontname in (:titlefont, :legendfont)
args = pop!(d, fontname, ())
for arg in wraptuple(args)
processFontArg!(d, fontname, arg)
end
end
# handle font args common to all axes
for fontname in (:tickfont, :guidefont)
args = pop!(d, fontname, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processFontArg!(d, Symbol(letter, fontname), arg)
end
end
end
# handle individual axes font args
for letter in (:x, :y, :z)
for fontname in (:tickfont, :guidefont)
args = pop!(d, Symbol(letter, fontname), ())
for arg in wraptuple(args)
processFontArg!(d, Symbol(letter, fontname), arg)
end
end
end
# handle line args
for arg in wraptuple(pop!(d, :line, ()))
processLineArg(d, arg)
@@ -701,6 +996,9 @@ function preprocessArgs!(d::KW)
delete!(d, :marker)
if haskey(d, :markershape)
d[:markershape] = _replace_markershape(d[:markershape])
if d[:markershape] == :none && d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
d[:markershape] = :circle
end
elseif anymarker
d[:markershape_to_add] = :circle # add it after _apply_recipe
end
@@ -744,10 +1042,15 @@ function preprocessArgs!(d::KW)
d[:colorbar] = convertLegendValue(d[:colorbar])
end
# framestyle
if haskey(d, :framestyle) && haskey(_framestyleAliases, d[:framestyle])
d[:framestyle] = _framestyleAliases[d[:framestyle]]
end
# warnings for moved recipes
st = get(d, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
warn("seriestype $st has been moved to StatPlots. To use: \`Pkg.add(\"StatPlots\"); using StatPlots\`")
@warn("seriestype $st has been moved to StatPlots. To use: \`Pkg.add(\"StatPlots\"); using StatPlots\`")
end
return
@@ -756,28 +1059,49 @@ end
# -----------------------------------------------------------------------------
"A special type that will break up incoming data into groups, and allow for easier creation of grouped plots"
type GroupBy
mutable struct GroupBy
groupLabels::Vector # length == numGroups
groupIds::Vector{Vector{Int}} # list of indices for each group
end
# this is when given a vector-type of values to group by
function extractGroupArgs(v::AVec, args...)
function extractGroupArgs(v::AVec, args...; legendEntry = string)
groupLabels = sort(collect(unique(v)))
n = length(groupLabels)
if n > 100
warn("You created n=$n groups... Is that intended?")
@warn("You created n=$n groups... Is that intended?")
end
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
GroupBy(map(string, groupLabels), groupIds)
GroupBy(map(legendEntry, groupLabels), groupIds)
end
legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
# this is when given a tuple of vectors of values to group by
function extractGroupArgs(vs::Tuple, args...)
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
v = map(tuple, vs...)
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
# allow passing NamedTuples for a named legend entry
@require NamedTuples = "73a701b4-84e1-5df0-88ff-1968ee2ee8dc" begin
legendEntryFromTuple(ns::NamedTuples.NamedTuple) =
join(["$k = $v" for (k, v) in zip(keys(ns), values(ns))], ", ")
function extractGroupArgs(vs::NamedTuples.NamedTuple, args...)
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
NT = eval(:(NamedTuples.@NT($(keys(vs)...)))){map(eltype, vs)...}
v = map(NT, vs...)
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
end
# expecting a mapping of "group label" to "group indices"
function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...)
function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
groupLabels = sortedkeys(idxmap)
groupIds = VecI[collect(idxmap[k]) for k in groupLabels]
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
GroupBy(groupLabels, groupIds)
end
@@ -818,7 +1142,7 @@ function warnOnUnsupported_args(pkg::AbstractBackend, d::KW)
if !isempty(_to_warn)
for k in sort(collect(_to_warn))
push!(already_warned, k)
warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_attrs(pkg))")
@warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_attrs(pkg))")
end
end
end
@@ -829,13 +1153,13 @@ end
function warnOnUnsupported(pkg::AbstractBackend, d::KW)
if !is_seriestype_supported(pkg, d[:seriestype])
warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))")
@warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))")
end
if !is_style_supported(pkg, d[:linestyle])
warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))")
@warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))")
end
if !is_marker_supported(pkg, d[:markershape])
warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))")
@warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))")
end
end
@@ -844,7 +1168,7 @@ function warnOnUnsupported_scales(pkg::AbstractBackend, d::KW)
if haskey(d, k)
v = d[k]
if !is_scale_supported(pkg, v)
warn("scale $v is unsupported with $pkg. Choose from: $(supported_scales(pkg))")
@warn("scale $v is unsupported with $pkg. Choose from: $(supported_scales(pkg))")
end
end
end
@@ -858,15 +1182,15 @@ function convertLegendValue(val::Symbol)
:best
elseif val in (:no, :none)
:none
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright)
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright)
val
else
error("Invalid symbol for legend: $val")
end
end
convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Void) = :none
convertLegendValue{S<:Real, T<:Real}(v::Tuple{S,T}) = v
convertLegendValue(val::Nothing) = :none
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# -----------------------------------------------------------------------------
@@ -935,12 +1259,17 @@ const _match_map = KW(
:background_color_legend => :background_color_subplot,
:background_color_inside => :background_color_subplot,
:foreground_color_legend => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_title => :foreground_color_subplot,
:left_margin => :margin,
:top_margin => :margin,
:right_margin => :margin,
:bottom_margin => :margin,
:titlefontfamily => :fontfamily_subplot,
:legendfontfamily => :fontfamily_subplot,
:titlefontcolor => :foreground_color_subplot,
:legendfontcolor => :foreground_color_subplot,
:tickfontcolor => :foreground_color_text,
:guidefontcolor => :foreground_color_guide,
)
# these can match values from the parent container (axis --> subplot --> plot)
@@ -949,8 +1278,13 @@ const _match_map2 = KW(
:foreground_color_subplot => :foreground_color,
:foreground_color_axis => :foreground_color_subplot,
:foreground_color_border => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_minor_grid=> :foreground_color_subplot,
:foreground_color_guide => :foreground_color_subplot,
:foreground_color_text => :foreground_color_subplot,
:fontfamily_subplot => :fontfamily,
:tickfontfamily => :fontfamily_subplot,
:guidefontfamily => :fontfamily_subplot,
)
# properly retrieve from plt.attr, passing `:match` to the correct key
@@ -1055,11 +1389,9 @@ end
function _update_subplot_periphery(sp::Subplot, anns::AVec)
# extend annotations, and ensure we always have a (x,y,PlotText) tuple
newanns = vcat(anns, sp[:annotations])
for (i,ann) in enumerate(newanns)
x,y,tmp = ann
ptxt = isa(tmp, PlotText) ? tmp : text(tmp)
newanns[i] = (x,y,ptxt)
newanns = []
for ann in vcat(anns, sp[:annotations])
append!(newanns, process_annotation(sp, ann...))
end
sp.attr[:annotations] = newanns
@@ -1083,7 +1415,6 @@ function _update_subplot_colors(sp::Subplot)
# foreground colors
color_or_nothing!(sp.attr, :foreground_color_subplot)
color_or_nothing!(sp.attr, :foreground_color_legend)
color_or_nothing!(sp.attr, :foreground_color_grid)
color_or_nothing!(sp.attr, :foreground_color_title)
return
end
@@ -1135,6 +1466,8 @@ function _update_axis_colors(axis::Axis)
color_or_nothing!(axis.d, :foreground_color_border)
color_or_nothing!(axis.d, :foreground_color_guide)
color_or_nothing!(axis.d, :foreground_color_text)
color_or_nothing!(axis.d, :foreground_color_grid)
color_or_nothing!(axis.d, :foreground_color_minor_grid)
return
end
@@ -1171,24 +1504,26 @@ end
# -----------------------------------------------------------------------------
has_black_border_for_default(st) = error("The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.")
has_black_border_for_default(st::Function) = error("The seriestype attribute only accepts Symbols, you passed the function $st.")
function has_black_border_for_default(st::Symbol)
like_histogram(st) || st in (:hexbin, :bar, :shape)
end
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, α, sp::Subplot, n::Int)
function getSeriesRGBColor(c, sp::Subplot, n::Int)
if c == :auto
c = autopick(sp[:color_palette], n)
elseif isa(c, Int)
c = autopick(sp[:color_palette], c)
end
plot_color(c, α)
plot_color(c)
end
function ensure_gradient!(d::KW, csym::Symbol, asym::Symbol)
if !isa(d[csym], ColorGradient)
d[csym] = cgrad(alpha = d[asym])
d[csym] = typeof(d[asym]) <: AbstractVector ? cgrad() : cgrad(alpha = d[asym])
end
end
@@ -1200,26 +1535,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)
@@ -1235,36 +1563,43 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
end
# update series color
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], d[:seriesalpha], sp, plotIndex)
d[:seriescolor] = getSeriesRGBColor.(d[:seriescolor], Ref(sp), plotIndex)
# update other colors
for s in (:line, :marker, :fill)
csym, asym = Symbol(s,:color), Symbol(s,:alpha)
d[csym] = if d[csym] == :match
d[csym] = if d[csym] == :auto
plot_color(if has_black_border_for_default(d[:seriestype]) && s == :line
sp[:foreground_color_subplot]
else
d[:seriescolor]
end, d[asym])
end)
elseif d[csym] == :match
plot_color(d[:seriescolor])
else
getSeriesRGBColor(d[csym], d[asym], sp, plotIndex)
getSeriesRGBColor.(d[csym], Ref(sp), plotIndex)
end
end
# 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], Ref(sp), plotIndex)
else
getSeriesRGBColor(d[:markerstrokecolor], d[:markerstrokealpha], sp, plotIndex)
getSeriesRGBColor.(d[:markerstrokecolor], Ref(sp), plotIndex)
end
# if marker_z or line_z are set, ensure we have a gradient
# if marker_z, fill_z or line_z are set, ensure we have a gradient
if d[:marker_z] != nothing
ensure_gradient!(d, :markercolor, :markeralpha)
end
if d[:line_z] != nothing
ensure_gradient!(d, :linecolor, :linealpha)
end
if d[:fill_z] != nothing
ensure_gradient!(d, :fillcolor, :fillalpha)
end
# scatter plots don't have a line, but must have a shape
if d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d)
@@ -1282,3 +1617,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
+271 -68
View File
@@ -70,14 +70,17 @@ function process_axis_arg!(d::KW, arg, letter = "")
elseif arg == nothing
d[Symbol(letter,:ticks)] = []
elseif T <: Bool || arg in _allShowaxisArgs
d[Symbol(letter,:showaxis)] = showaxis(arg, letter)
elseif typeof(arg) <: Number
d[Symbol(letter,:rotation)] = arg
elseif typeof(arg) <: Function
d[Symbol(letter,:formatter)] = arg
else
warn("Skipped $(letter)axis arg $arg")
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_axis))
@warn("Skipped $(letter)axis arg $arg")
end
end
@@ -181,15 +184,27 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
end
# get a list of well-laid-out ticks
scaled_ticks = if ticks == nothing
optimize_ticks(
if ticks == nothing
scaled_ticks = optimize_ticks(
sf(amin),
sf(amax);
k_min = 5, # minimum number of ticks
k_min = 4, # minimum number of ticks
k_max = 8, # maximum number of ticks
)[1]
elseif typeof(ticks) <: Int
scaled_ticks, viewmin, viewmax = optimize_ticks(
sf(amin),
sf(amax);
k_min = ticks, # minimum number of ticks
k_max = ticks, # maximum number of ticks
k_ideal = ticks,
# `strict_span = false` rewards cases where the span of the
# chosen ticks is not too much bigger than amin - amax:
strict_span = false,
)
axis[:lims] = map(invscalefunc(scale), (viewmin, viewmax))
else
map(sf, filter(t -> amin <= t <= amax, ticks))
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end
unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
@@ -197,12 +212,20 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
formatter = axis[:formatter]
if formatter == :auto
# the default behavior is to make strings of the scaled values and then apply the labelfunc
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, :auto))
elseif formatter == :plain
# Leave the numbers in plain format
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, :plain))
elseif formatter == :scientific
Showoff.showoff(unscaled_ticks, :scientific)
else
# there was an override for the formatter... use that on the unscaled ticks
map(formatter, unscaled_ticks)
# if the formatter left us with numbers, still apply the default formatter
# However it leave us with the problem of unicode number decoding by the backend
# if eltype(unscaled_ticks) <: Number
# Showoff.showoff(unscaled_ticks, :auto)
# end
end
else
# no finite ticks to show...
@@ -216,19 +239,38 @@ end
# return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(axis::Axis)
ticks = axis[:ticks]
ticks = _transform_ticks(axis[:ticks])
ticks in (nothing, false) && return nothing
# treat :native ticks as :auto
ticks = ticks == :native ? :auto : ticks
dvals = axis[:discrete_values]
cv, dv = if !isempty(dvals) && ticks == :auto
# discrete ticks...
axis[:continuous_values], dvals
elseif ticks == :auto
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
elseif typeof(ticks) <: AVec
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
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
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
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
@@ -237,13 +279,39 @@ function get_ticks(axis::Axis)
end
# @show ticks dvals cv dv
# TODO: better/smarter cutoff values for sampling ticks
if length(cv) > 30 && ticks == :auto
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)]
cv[rng], dv[rng]
return cv, dv
end
_transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
function get_minor_ticks(axis,ticks)
axis[:minorticks] in (nothing, false) && !axis[:minorgrid] && return nothing
ticks = ticks[1]
length(ticks) < 2 && return nothing
amin, amax = axis_limits(axis)
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
if length(ticks) > 2
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
elseif axis[:scale] == :none
ratio = 1
else
cv, dv
return nothing
end
first_step = ticks[2] - ticks[1]
last_step = ticks[end] - ticks[end-1]
ticks = [ticks[1] - first_step/ratio; ticks; ticks[end] + last_step*ratio]
#Default to 5 intervals between major ticks
n = typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : 5
minorticks = typeof(ticks[1])[]
for (i,hi) in enumerate(ticks[2:end])
lo = ticks[i]
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
end
minorticks[amin .<= minorticks .<= amax]
end
# -------------------------------------------------------------------------
@@ -260,8 +328,8 @@ end
function expand_extrema!(ex::Extrema, v::Number)
ex.emin = NaNMath.min(v, ex.emin)
ex.emax = NaNMath.max(v, ex.emax)
ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin
ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax
ex
end
@@ -270,17 +338,17 @@ 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]
function expand_extrema!{MIN<:Number,MAX<:Number}(axis::Axis, v::Tuple{MIN,MAX})
function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
ex = axis[:extrema]
ex.emin = NaNMath.min(v[1], ex.emin)
ex.emax = NaNMath.max(v[2], ex.emax)
ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin
ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax
ex
end
function expand_extrema!{N<:Number}(axis::Axis, v::AVec{N})
function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
ex = axis[:extrema]
for vi in v
expand_extrema!(ex, vi)
@@ -299,6 +367,9 @@ function expand_extrema!(sp::Subplot, d::KW)
else
letter == :x ? :y : letter == :y ? :x : :z
end]
if letter != :z && d[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
data = [NaN]
end
axis = sp[Symbol(letter, "axis")]
if isa(data, Volume)
@@ -331,7 +402,7 @@ function expand_extrema!(sp::Subplot, d::KW)
if fr == nothing && d[:seriestype] == :bar
fr = 0.0
end
if fr != nothing
if fr != nothing && !all3D(d)
axis = sp.attr[vert ? :yaxis : :xaxis]
if typeof(fr) <: Tuple
for fri in fr
@@ -349,13 +420,22 @@ function expand_extrema!(sp::Subplot, d::KW)
bw = d[:bar_width]
if bw == nothing
bw = d[:bar_width] = ignorenan_mean(diff(data))
bw = d[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
end
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end
# expand for heatmaps
if d[:seriestype] == :heatmap
for letter in (:x, :y)
data = d[letter]
axis = sp[Symbol(letter, "axis")]
scale = get(d, Symbol(letter, "scale"), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
end
function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax)
@@ -366,21 +446,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
@@ -389,6 +471,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]
@@ -408,8 +497,19 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
if !isfinite(amin) && !isfinite(amax)
amin, amax = 0.0, 1.0
end
if should_widen
widen(amin, amax)
if ispolar(axis.sps[1])
if axis[:letter] == :x
amin, amax = 0, 2pi
elseif lims == :auto
#widen max radius so ticks dont overlap with theta axis
amin, amax + 0.1 * abs(amax - amin)
else
amin, amax
end
elseif should_widen && axis[:widen]
widen(amin, amax, axis[:scale])
elseif lims == :round
round_limits(amin,amax)
else
amin, amax
end
@@ -490,38 +590,141 @@ function axis_drawing_info(sp::Subplot)
ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
spine_segs = Segments(2)
grid_segs = Segments(2)
xminorticks = get_minor_ticks(xaxis,xticks)
yminorticks = get_minor_ticks(yaxis,yticks)
xaxis_segs = Segments(2)
yaxis_segs = Segments(2)
xtick_segs = Segments(2)
ytick_segs = Segments(2)
xgrid_segs = Segments(2)
ygrid_segs = Segments(2)
xminorgrid_segs = Segments(2)
yminorgrid_segs = Segments(2)
xborder_segs = Segments(2)
yborder_segs = Segments(2)
if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
t1 = invf(f(ymin) + 0.015*(f(ymax)-f(ymin)))
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin)))
if sp[:framestyle] != :none
# xaxis
if xaxis[:showaxis]
if sp[:framestyle] != :grid
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
end
push!(xaxis_segs, (xmin, y1), (xmax, y1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(xticks in (nothing,false)) && length(xticks) > 1
showticks = xticks[1] .!= 0
xticks = (xticks[1][showticks], xticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2), (xmax, y2)) # top spine
end
if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(ymin) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t2 = invf(f(ymax) - 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
# push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
for xtick in xticks[1]
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid
# push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
for xtick in xticks[1]
if xaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
end
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end
end
if !(xaxis[:minorticks] in (nothing, false)) || xaxis[:minorgrid]
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(ymin) + 0.01 * (f(ymax) - f(ymin)) * ticks_in)
t2 = invf(f(ymax) - 0.01 * (f(ymax) - f(ymin)) * ticks_in)
t3 = invf(f(0) + 0.01 * (f(ymax) - f(ymin)) * ticks_in)
for xminortick in xminorticks
if xaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xminortick, tick_start), (xminortick, tick_stop)) # bottom tick
end
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:minorgrid] && push!(xminorgrid_segs, (xminortick, ymin), (xminortick, ymax)) # vertical grid
end
end
# yaxis
if yaxis[:showaxis]
if sp[:framestyle] != :grid
x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
end
push!(yaxis_segs, (x1, ymin), (x1, ymax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(yticks in (nothing,false)) && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin), (x2, ymax)) # right spine
end
if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(xmin) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t2 = invf(f(xmax) - 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
for ytick in yticks[1]
if yaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
end
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
if !(yaxis[:minorticks] in (nothing, false)) || yaxis[:minorgrid]
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(xmin) + 0.01 * (f(xmax) - f(xmin)) * ticks_in)
t2 = invf(f(xmax) - 0.01 * (f(xmax) - f(xmin)) * ticks_in)
t3 = invf(f(0) + 0.01 * (f(xmax) - f(xmin)) * ticks_in)
for ytick in yminorticks
if yaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
end
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
end
if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
t1 = invf(f(xmin) + 0.015*(f(xmax)-f(xmin)))
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
# push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
for ytick in yticks[1]
push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick
push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
# push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
end
end
xticks, yticks, spine_segs, grid_segs
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs
end
+164 -51
View File
@@ -1,42 +1,52 @@
using Pkg
immutable NoBackend <: AbstractBackend end
struct NoBackend <: AbstractBackend end
const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[]
const _initialized_backends = Set{Symbol}()
const _default_backends = (:none, :gr, :plotly)
const _backendPackage = Dict{Symbol, Symbol}()
"Returns a list of supported backends"
backends() = _backends
"Returns the name of the current backend"
backend_name() = CURRENT_BACKEND.sym
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
backend_package(pkg::Symbol) = pkg in _default_backends ? :Plots : Symbol("Plots", _backendPackage[pkg])
backend_package_name(sym::Symbol) = sym in _default_backends ? :Plots : _backendPackage[sym]
macro init_backend(s)
str = lowercase(string(s))
package_str = string(s)
str = lowercase(package_str)
sym = Symbol(str)
T = Symbol(string(s) * "Backend")
esc(quote
immutable $T <: AbstractBackend end
struct $T <: AbstractBackend end
export $sym
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
backend_name(::$T) = Symbol($str)
backend_package_name(pkg::$T) = backend_package_name(Symbol($str))
push!(_backends, Symbol($str))
_backendType[Symbol($str)] = $T
_backendSymbol[$T] = Symbol($str)
include("backends/" * $str * ".jl")
_backendPackage[Symbol($str)] = Symbol($package_str)
# include("backends/" * $str * ".jl")
end)
end
include("backends/web.jl")
# include("backends/web.jl")
# include("backends/supported.jl")
# ---------------------------------------------------------
function add_backend(pkg::Symbol)
info("To do a standard install of $pkg, copy and run this:\n\n")
@info("To do a standard install of $pkg, copy and run this:\n\n")
println(add_backend_string(_backend_instance(pkg)))
println()
end
add_backend_string(b::AbstractBackend) = warn("No custom install defined for $(backend_name(b))")
# don't do anything as a default
_create_backend_figure(plt::Plot) = nothing
@@ -48,8 +58,8 @@ _series_updated(plt::Plot, series::Series) = nothing
_before_layout_calcs(plt::Plot) = nothing
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefontsize] * pt
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefontsize] * pt
"Returns the (width,height) of a text label."
function text_size(lablen::Int, sz::Number, rot::Number = 0)
@@ -90,7 +100,7 @@ function tick_padding(axis::Axis)
# hgt
# get the height of the rotated label
text_size(longest_label, axis[:tickfont].pointsize, rot)[2]
text_size(longest_label, axis[:tickfontsize], rot)[2]
end
end
@@ -120,7 +130,7 @@ _update_plot_object(plt::Plot) = nothing
# ---------------------------------------------------------
type CurrentBackend
mutable struct CurrentBackend
sym::Symbol
pkg::AbstractBackend
end
@@ -131,31 +141,30 @@ 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
sym = Symbol(lowercase(env_default))
if haskey(_backendType, sym)
sym = Symbol(lowercase(env_default))
if sym in _backends
if sym in _initialized_backends
return backend(sym)
else
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"))
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
end
catch
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not installed.")
else
@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
end
# the ordering/inclusion of this package list is my semi-arbitrary guess at
# which one someone will want to use if they have the package installed...accounting for
# features, speed, and robustness
for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
if Pkg.installed(pkgstr) != nothing
return backend(Symbol(lowercase(pkgstr)))
end
end
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
# if pkgstr in keys(Pkg.installed())
# return backend(Symbol(lowercase(pkgstr)))
# end
# end
# the default if nothing else is installed
backend(:plotly)
backend(:gr)
end
@@ -171,24 +180,6 @@ function backend()
pickDefaultBackend()
end
sym = CURRENT_BACKEND.sym
if !(sym in _initialized_backends)
# # initialize
# println("[Plots.jl] Initializing backend: ", sym)
inst = _backend_instance(sym)
try
_initialize_backend(inst)
catch err
warn("Couldn't initialize $sym. (might need to install it?)")
add_backend(sym)
rethrow(err)
end
push!(_initialized_backends, sym)
end
CURRENT_BACKEND.pkg
end
@@ -196,16 +187,29 @@ end
Set the plot backend.
"""
function backend(pkg::AbstractBackend)
CURRENT_BACKEND.sym = backend_name(pkg)
warn_on_deprecated_backend(CURRENT_BACKEND.sym)
CURRENT_BACKEND.pkg = pkg
sym = backend_name(pkg)
if sym in _initialized_backends
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
else
# try
_initialize_backend(pkg)
push!(_initialized_backends, sym)
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
# catch
# add_backend(sym)
# end
end
backend()
end
function backend(modname::Symbol)
warn_on_deprecated_backend(modname)
CURRENT_BACKEND.sym = modname
CURRENT_BACKEND.pkg = _backend_instance(modname)
function backend(sym::Symbol)
if sym in _backends
backend(_backend_instance(sym))
else
@warn("`:$sym` is not a supported backend.")
end
backend()
end
@@ -213,7 +217,7 @@ const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
function warn_on_deprecated_backend(bsym::Symbol)
if bsym in _deprecated_backends
warn("Backend $bsym has been deprecated. It may not work as originally intended.")
@warn("Backend $bsym has been deprecated. It may not work as originally intended.")
end
end
@@ -305,3 +309,112 @@ end
# is_subplot_supported(::AbstractBackend) = false
# is_subplot_supported() = is_subplot_supported(backend())
################################################################################
# initialize the backends
function _initialize_backend(pkg::AbstractBackend)
sym = backend_package_name(pkg)
@eval Main begin
import $sym
export $sym
end
end
function add_backend_string(pkg::AbstractBackend)
sym = backend_package_name(pkg)
"""
using Pkg
Pkg.add("$sym")
"""
end
# ------------------------------------------------------------------------------
# glvisualize
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval Main begin
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
import FileIO, Images
export GLVisualize
import Reactive: Signal
import GLAbstraction: Style
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
end
end
# ------------------------------------------------------------------------------
# hdf5
function _initialize_backend(::HDF5Backend)
@eval Main begin
import HDF5
export HDF5
end
end
# ------------------------------------------------------------------------------
# PGFPLOTS
function add_backend_string(::PGFPlotsBackend)
"""
using Pkg
Pkg.add("PGFPlots")
Pkg.build("PGFPlots")
"""
end
# ------------------------------------------------------------------------------
# plotlyjs
function add_backend_string(::PlotlyJSBackend)
"""
using Pkg
Pkg.add("PlotlyJS")
Pkg.add("Rsvg")
import Blink
Blink.AtomShell.install()
"""
end
# ------------------------------------------------------------------------------
# pyplot
function _initialize_backend(::PyPlotBackend)
@eval Main begin
import PyPlot, PyCall
import LaTeXStrings: latexstring
export PyPlot
# we don't want every command to update the figure
PyPlot.ioff()
end
end
function add_backend_string(::PyPlotBackend)
"""
using Pkg
Pkg.add("PyPlot")
Pkg.add("PyCall")
Pkg.add("LaTeXStrings")
withenv("PYTHON" => "") do
Pkg.build("PyCall")
Pkg.build("PyPlot")
end
"""
end
# ------------------------------------------------------------------------------
# unicodeplots
function add_backend_string(::UnicodePlotsBackend)
"""
using Pkg
Pkg.add("UnicodePlots")
Pkg.build("UnicodePlots")
"""
end
+149 -108
View File
@@ -20,11 +20,15 @@ const _glvisualize_attr = merge_with_base_supported([
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:title, :title_location,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:titlefontsize, :titlefontcolor,
:legendfontsize, :legendfontcolor,
:tickfontsize,
:guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :colorbar,
:marker_z,
:line_z,
:levels,
@@ -38,10 +42,12 @@ const _glvisualize_attr = merge_with_base_supported([
:clims,
:inset_subplots,
:dpi,
:hover
:hover,
:framestyle,
:tick_direction,
])
const _glvisualize_seriestype = [
:path, :shape,
:path, :shape, :straightline,
:scatter, :hexbin,
:bar, :boxplot,
:heatmap, :image, :volume,
@@ -51,37 +57,11 @@ const _glvisualize_style = [:auto, :solid, :dash, :dot, :dashdot]
const _glvisualize_marker = _allMarkers
const _glvisualize_scale = [:identity, :ln, :log2, :log10]
# --------------------------------------------------------------------------------------
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval begin
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle
import FileIO, Images
export GLVisualize
import Reactive: Signal
import GLAbstraction: Style
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
Plots.slice_arg(img::Images.AbstractImage, idx::Int) = img
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported{Img<:Images.AbstractImage}(::GLVisualizeBackend, shape::Union{Vector{Img}, Img}) = true
is_marker_supported{C<:Colorant}(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
const GL = Plots
end
end
function add_backend_string(b::GLVisualizeBackend)
"""
if !Plots.is_installed("GLVisualize")
Pkg.add("GLVisualize")
end
"""
end
slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
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
GL = Plots
# ---------------------------------------------------------------------------
@@ -173,12 +153,12 @@ function gl_marker(shape)
shape
end
function gl_marker(shape::Shape)
points = Point2f0[Vec{2,Float32}(p) for p in zip(shape.x, shape.y)]
points = Point2f0[GeometryTypes.Vec{2, Float32}(p) for p in zip(shape.x, shape.y)]
bb = GeometryTypes.AABB(points)
mini, maxi = minimum(bb), maximum(bb)
w3 = maxi-mini
origin, width = Point2f0(mini[1], mini[2]), Point2f0(w3[1], w3[2])
map!(p -> ((p - origin) ./ width) - 0.5f0, points) # normalize and center
map!(p -> ((p - origin) ./ width) - 0.5f0, points, points) # normalize and center
GeometryTypes.GLNormalMesh(points)
end
# create a marker/shape type
@@ -212,13 +192,13 @@ function extract_limits(sp, d, kw_args)
nothing
end
to_vec{T <: FixedVector}(::Type{T}, vec::T) = vec
to_vec{T <: FixedVector}(::Type{T}, s::Number) = T(s)
to_vec(::Type{T}, vec::T) where {T <: StaticArrays.StaticVector} = vec
to_vec(::Type{T}, s::Number) where {T <: StaticArrays.StaticVector} = T(s)
to_vec{T <: FixedVector{2}}(::Type{T}, vec::FixedVector{3}) = T(vec[1], vec[2])
to_vec{T <: FixedVector{3}}(::Type{T}, vec::FixedVector{2}) = T(vec[1], vec[2], 0)
to_vec(::Type{T}, vec::StaticArrays.StaticVector{3}) where {T <: StaticArrays.StaticVector{2}} = T(vec[1], vec[2])
to_vec(::Type{T}, vec::StaticArrays.StaticVector{2}) where {T <: StaticArrays.StaticVector{3}} = T(vec[1], vec[2], 0)
to_vec{T <: FixedVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
to_vec(::Type{T}, vecs::AbstractVector) where {T <: StaticArrays.StaticVector} = map(x-> to_vec(T, x), vecs)
function extract_marker(d, kw_args)
dim = Plots.is3d(d) ? 3 : 2
@@ -273,15 +253,21 @@ end
function extract_surface(d)
map(_extract_surface, (d[:x], d[:y], d[:z]))
end
function topoints{P}(::Type{P}, array)
P[x for x in zip(array...)]
function topoints(::Type{P}, array) where P
[P(x) for x in zip(array...)]
end
function extract_points(d)
dim = is3d(d) ? 3 : 2
array = (d[:x], d[:y], d[:z])[1:dim]
array = if d[:seriestype] == :straightline
straightline_data(d)
elseif d[:seriestype] == :shape
shape_data(d)
else
(d[:x], d[:y], d[:z])[1:dim]
end
topoints(Point{dim, Float32}, array)
end
function make_gradient{C <: Colorant}(grad::Vector{C})
function make_gradient(grad::Vector{C}) where C <: Colorant
grad
end
function make_gradient(grad::ColorGradient)
@@ -327,7 +313,7 @@ end
function extract_stroke(d, kw_args)
extract_c(d, kw_args, :line)
if haskey(d, :linewidth)
kw_args[:thickness] = d[:linewidth] * 3
kw_args[:thickness] = Float32(d[:linewidth] * 3)
end
end
@@ -336,7 +322,7 @@ function extract_color(d, sym)
end
gl_color(c::PlotUtils.ColorGradient) = c.colors
gl_color{T<:Colorant}(c::Vector{T}) = c
gl_color(c::Vector{T}) where {T<:Colorant} = c
gl_color(c::RGBA{Float32}) = c
gl_color(c::Colorant) = RGBA{Float32}(c)
@@ -382,7 +368,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
@@ -395,7 +381,7 @@ function extract_linestyle(d, kw_args)
haskey(d, :linestyle) || return
ls = d[:linestyle]
lw = d[:linewidth]
kw_args[:thickness] = lw
kw_args[:thickness] = Float32(lw)
if ls == :dash
points = [0.0, lw, 2lw, 3lw, 4lw]
insert_pattern!(points, kw_args)
@@ -567,7 +553,7 @@ function draw_grid_lines(sp, grid_segs, thickness, style, model, color)
)
d = Dict(
:linestyle => style,
:linewidth => thickness,
:linewidth => Float32(thickness),
:linecolor => color
)
Plots.extract_linestyle(d, kw_args)
@@ -576,8 +562,10 @@ end
function align_offset(startpos, lastpos, atlas, rscale, font, align)
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
xmove = (lastpos-startpos)[1]+xscale
if align == :top
xmove = (lastpos-startpos)[1] + xscale
if isa(align, GeometryTypes.Vec)
return -Vec2f0(xmove, yscale) .* align
elseif align == :top
return -Vec2f0(xmove/2f0, yscale)
elseif align == :right
return -Vec2f0(xmove, yscale/2f0)
@@ -586,11 +574,6 @@ function align_offset(startpos, lastpos, atlas, rscale, font, align)
end
end
function align_offset(startpos, lastpos, atlas, rscale, font, align::Vec)
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
xmove = (lastpos-startpos)[1] + xscale
return -Vec2f0(xmove, yscale) .* align
end
function alignment2num(x::Symbol)
(x in (:hcenter, :vcenter)) && return 0.5
@@ -606,10 +589,10 @@ end
pointsize(font) = font.pointsize * 2
function draw_ticks(
axis, ticks, isx, lims, m, text = "",
axis, ticks, isx, isorigin, lims, m, text = "",
positions = Point2f0[], offsets=Vec2f0[]
)
sz = pointsize(axis[:tickfont])
sz = pointsize(tickfont(axis))
atlas = GLVisualize.get_texture_atlas()
font = GLVisualize.defaultfont()
@@ -624,7 +607,11 @@ function draw_ticks(
for (cv, dv) in zip(ticks...)
x, y = cv, lims[1]
xy = isx ? (x, y) : (y, x)
xy = if isorigin
isx ? (x, 0) : (0, x)
else
isx ? (x, y) : (y, x)
end
_pos = m * GeometryTypes.Vec4f0(xy[1], xy[2], 0, 1)
startpos = Point2f0(_pos[1], _pos[2]) - axis_gap
str = string(dv)
@@ -638,7 +625,7 @@ function draw_ticks(
position = GLVisualize.calc_position(str, startpos, sz, font, atlas)
offset = GLVisualize.calc_offset(str, sz, font, atlas)
alignoff = align_offset(startpos, last(position), atlas, sz, font, align)
map!(position) do pos
map!(position, position) do pos
pos .+ alignoff
end
append!(positions, position)
@@ -660,7 +647,7 @@ function glvisualize_text(position, text, kw_args)
offset = GLVisualize.calc_offset(text.str, rscale, font, atlas)
alignoff = align_offset(startpos, last(position), atlas, rscale, font, text_align)
map!(position) do pos
map!(position, position) do pos
pos .+ alignoff
end
kw_args[:position] = position
@@ -680,48 +667,106 @@ function text_model(font, pivot)
end
end
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
xticks, yticks, spine_segs, grid_segs = Plots.axis_drawing_info(sp)
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
c = Colors.color(Plots.gl_color(sp[:foreground_color_grid]))
xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
ygc = Colors.color(Plots.gl_color(yaxis[:foreground_color_grid]))
axis_vis = []
if sp[:grid]
grid = draw_grid_lines(sp, grid_segs, 1f0, :dot, model, RGBA(c, 0.3f0))
if xaxis[:grid]
grid = draw_grid_lines(sp, xgrid_segs, xaxis[:gridlinewidth], xaxis[:gridstyle], model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, grid)
end
if alpha(xaxis[:foreground_color_border]) > 0
spine = draw_grid_lines(sp, spine_segs, 1f0, :solid, model, RGBA(c, 1.0f0))
if yaxis[:grid]
grid = draw_grid_lines(sp, ygrid_segs, yaxis[:gridlinewidth], yaxis[:gridstyle], model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, grid)
end
if xaxis[:minorgrid]
minorgrid = draw_minorgrid_lines(sp, xminorgrid_segs, xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], model, RGBA(xgc, xaxis[:minorgridalpha]))
push!(axis_vis, minorgrid)
end
if yaxis[:minorgrid]
minorgrid = draw_minorgrid_lines(sp, yminorgrid_segs, yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], model, RGBA(ygc, yaxis[:minorgridalpha]))
push!(axis_vis, minorgrid)
end
xac = Colors.color(Plots.gl_color(xaxis[:foreground_color_axis]))
yac = Colors.color(Plots.gl_color(yaxis[:foreground_color_axis]))
if alpha(xaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, xspine_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, yspine_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine)
end
if sp[:framestyle] in (:zerolines, :grid)
if alpha(xaxis[:foreground_color_grid]) > 0
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_grid]) > 0
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, spine)
end
else
if alpha(xaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine)
end
end
fcolor = Plots.gl_color(xaxis[:foreground_color_axis])
xlim = Plots.axis_limits(xaxis)
ylim = Plots.axis_limits(yaxis)
if !(xaxis[:ticks] in (nothing, false, :none))
if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) && xaxis[:showaxis]
ticklabels = map(model) do m
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(xaxis, xticks, true, ylim, m)
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(
yaxis, yticks, false, xlim, m,
t, positions, offsets
)
t, positions, offsets = draw_ticks(xaxis, xticks, true, sp[:framestyle] == :origin, ylim, m)
end
kw_args = Dict{Symbol, Any}(
:position => map(x-> x[2], ticklabels),
:offset => map(last, ticklabels),
:color => fcolor,
:relative_scale => pointsize(xaxis[:tickfont]),
:relative_scale => pointsize(tickfont(xaxis)),
:scale_primitive => false
)
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end
if !(yaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) && yaxis[:showaxis]
ticklabels = map(model) do m
mirror = yaxis[:mirror]
t, positions, offsets = draw_ticks(yaxis, yticks, false, sp[:framestyle] == :origin, xlim, m)
end
kw_args = Dict{Symbol, Any}(
:position => map(x-> x[2], ticklabels),
:offset => map(last, ticklabels),
:color => fcolor,
:relative_scale => pointsize(tickfont(xaxis)),
:scale_primitive => false
)
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end
xbc = Colors.color(Plots.gl_color(xaxis[:foreground_color_border]))
ybc = Colors.color(Plots.gl_color(yaxis[:foreground_color_border]))
intensity = sp[:framestyle] == :semi ? 0.5f0 : 1.0f0
if sp[:framestyle] in (:box, :semi)
xborder = draw_grid_lines(sp, xborder_segs, intensity, :solid, model, RGBA(xbc, intensity))
yborder = draw_grid_lines(sp, yborder_segs, intensity, :solid, model, RGBA(ybc, intensity))
push!(axis_vis, xborder, yborder)
end
area_w = GeometryTypes.widths(area)
if sp[:title] != ""
tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title])
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, tf.rotation, color)
tf = titlefont(sp)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, tf.rotation, tf.color)
xy = Point2f0(area.w/2, area_w[2] + pointsize(tf)/2)
kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
extract_font(font, kw)
@@ -729,9 +774,9 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
push!(axis_vis, glvisualize_text(xy, t, kw))
end
if xaxis[:guide] != ""
tf = xaxis[:guidefont]; color = gl_color(xaxis[:foreground_color_guide])
tf = guidefont(xaxis)
xy = Point2f0(area.w/2, - pointsize(tf)/2)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :bottom, tf.rotation, color)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :bottom, tf.rotation, tf.color)
kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
t = PlotText(xaxis[:guide], font)
extract_font(font, kw)
@@ -739,8 +784,8 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
end
if yaxis[:guide] != ""
tf = yaxis[:guidefont]; color = gl_color(yaxis[:foreground_color_guide])
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, 90f0, color)
tf = guidefont(yaxis)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, 90f0, tf.color)
xy = Point2f0(-pointsize(tf)/2, area.h/2)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>true)
t = PlotText(yaxis[:guide], font)
@@ -792,7 +837,7 @@ function gl_bar(d, kw_args)
fillto = 0
end
# create the bar shapes by adding x/y segments
positions, scales = Array(Point2f0, ny), Array(Vec2f0, ny)
positions, scales = Array{Point2f0}(ny), Array{Vec2f0}(ny)
m = Reactive.value(kw_args[:model])
sx, sy = m[1,1], m[2,2]
for i=1:ny
@@ -835,12 +880,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
@@ -939,11 +984,11 @@ 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
offsets = Array(Vec2f0, length(anns.strs))
offsets = Array{Vec2f0}(length(anns.strs))
series[:markersize] = map(1:length(anns.strs)) do i
str = _cycle(anns.strs, i)
# get the width and height of the string (in mm)
@@ -1042,7 +1087,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
kw_args[:stroke_width] = Float32(d[:linewidth]/100f0)
end
vis = GL.gl_surface(x, y, z, kw_args)
elseif (st in (:path, :path3d)) && d[:linewidth] > 0
elseif (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
kw = copy(kw_args)
points = Plots.extract_points(d)
extract_linestyle(d, kw)
@@ -1122,7 +1167,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
anns = series[:series_annotations]
for (x, y, str, font) in EachAnn(anns, d[:x], d[:y])
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
x, y = Reactive.value(model_m) * Vec{4, Float32}(x, y, 0, 1)
x, y = Reactive.value(model_m) * GeometryTypes.Vec{4, Float32}(x, y, 0, 1)
extract_font(font, txt_args)
t = glvisualize_text(Point2f0(x, y), PlotText(str, font), txt_args)
GLVisualize._view(t, sp_screen, camera = :perspective)
@@ -1148,21 +1193,18 @@ function _show(io::IO, ::MIME"image/png", plt::Plot{GLVisualizeBackend})
GLWindow.render_frame(GLWindow.rootscreen(plt.o))
GLWindow.swapbuffers(plt.o)
buff = GLWindow.screenbuffer(plt.o)
png = Images.Image(map(RGB{U8}, buff),
colorspace = "sRGB",
spatialorder = ["y", "x"]
)
png = map(RGB{U8}, buff)
FileIO.save(FileIO.Stream(FileIO.DataFormat{:PNG}, io), png)
end
function gl_image(img, kw_args)
rect = kw_args[:primitive]
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(rect.x, rect.y, rect.h, rect.w) # seems to be flipped
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(rect.x, rect.y, rect.w, rect.h)
visualize(img, Style(:default), kw_args)
end
function handle_segment{P}(lines, line_segments, points::Vector{P}, segment)
function handle_segment(lines, line_segments, points::Vector{P}, segment) where P
(isempty(segment) || length(segment) < 2) && return
if length(segment) == 2
append!(line_segments, view(points, segment))
@@ -1258,7 +1300,7 @@ function gl_poly(points, kw_args)
if !isempty(GeometryTypes.faces(mesh)) # check if polygonation has any faces
push!(result, GLVisualize.visualize(mesh, Style(:default), kw_args))
else
warn("Couldn't draw the polygon: $points")
@warn("Couldn't draw the polygon: $points")
end
end
result
@@ -1268,7 +1310,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
@@ -1284,7 +1326,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))
@@ -1293,7 +1335,7 @@ function gl_surface(x,y,z, kw_args)
end
color = get(kw_args, :stroke_color, RGBA{Float32}(0,0,0,1))
kw_args[:color] = color
kw_args[:thickness] = get(kw_args, :stroke_width, 1f0)
kw_args[:thickness] = Float32(get(kw_args, :stroke_width, 1f0))
kw_args[:indices] = faces
delete!(kw_args, :stroke_color)
delete!(kw_args, :stroke_width)
@@ -1309,8 +1351,8 @@ function gl_contour(x, y, z, kw_args)
if kw_args[:fillrange] != nothing
delete!(kw_args, :intensity)
I = GLVisualize.Intensity{1, Float32}
main = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
I = GLVisualize.Intensity{Float32}
main = [I(z[j,i]) for i=1:size(z, 2), j=1:size(z, 1)]
return visualize(main, Style(:default), kw_args)
else
@@ -1342,7 +1384,7 @@ function gl_heatmap(x,y,z, kw_args)
get!(kw_args, :color_norm, Vec2f0(ignorenan_extrema(z)))
get!(kw_args, :color_map, Plots.make_gradient(cgrad()))
delete!(kw_args, :intensity)
I = GLVisualize.Intensity{1, Float32}
I = GLVisualize.Intensity{Float32}
heatmap = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
tex = GLAbstraction.Texture(heatmap, minfilter=:nearest)
kw_args[:stroke_width] = 0f0
@@ -1403,7 +1445,7 @@ function make_label(sp, series, i)
d = series.d
st = d[:seriestype]
kw_args = KW()
if (st in (:path, :path3d)) && d[:linewidth] > 0
if (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
points = Point2f0[(0, ho), (w, ho)]
kw = KW()
extract_linestyle(d, kw)
@@ -1429,9 +1471,8 @@ function make_label(sp, series, i)
else
series[:label]
end
color = sp[:foreground_color_legend]
ft = sp[:legendfont]
font = Plots.Font(ft.family, ft.pointsize, :left, :bottom, 0.0, color)
ft = legendfont(sp)
font = Plots.Font(ft.family, ft.pointsize, :left, :bottom, 0.0, ft.color)
xy = Point2f0(w+gap, 0.0)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>false)
extract_font(font, kw)
+463 -206
View File
File diff suppressed because it is too large Load Diff
+73 -79
View File
@@ -28,20 +28,20 @@ Read from .hdf5 file using:
- Should be reliable for archival purposes.
==#
import FixedPointNumbers: N0f8 #In core Julia
#Dispatch types:
immutable HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
immutable HDF5CTuple; end #Identifies a "complex" tuple structure
struct HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
struct HDF5CTuple; end #Identifies a "complex" tuple structure
type HDF5Plot_PlotRef
ref::Union{Plot, Void}
mutable struct HDF5Plot_PlotRef
ref::Union{Plot, Nothing}
end
#==Useful constants
===============================================================================#
const _hdf5_nullable{T} = Union{T, Nothing}
const _hdf5_plotroot = "plot"
const _hdf5_dataroot = "data" #TODO: Eventually move data to different root (easier to locate)?
const _hdf5plot_datatypeid = "TYPE" #Attribute identifying type
@@ -94,7 +94,7 @@ const _hdf5_attr = merge_with_base_supported([
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape,
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
@@ -105,12 +105,35 @@ const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::HDF5Backend, shape::Shape) = true
function add_backend_string(::HDF5Backend)
"""
if !Plots.is_installed("HDF5")
Pkg.add("HDF5")
end
"""
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
telem2str = Dict{String, Type}(
"NATIVE" => HDF5PlotNative,
"VOID" => Nothing,
"BOOL" => Bool,
"SYMBOL" => Symbol,
"TUPLE" => Tuple,
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
"RGBA" => ARGB{N0f8},
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
#Sub-structure types:
"FONT" => Font,
"BOUNDINGBOX" => BoundingBox,
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
"SUBPLOT" => Subplot,
"NULLABLE" => _hdf5_nullable,
)
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
end
@@ -128,7 +151,7 @@ function _hdf5_merge!(dest::Dict, src::Dict)
_hdf5_merge!(dest[k].d, v.d)
else
dest[k] = v
end
end
end
return
end
@@ -137,43 +160,6 @@ end
#==
===============================================================================#
function _initialize_backend(::HDF5Backend)
@eval begin
import HDF5
export HDF5
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
const telem2str = Dict{String, Type}(
"NATIVE" => HDF5PlotNative,
"VOID" => Void,
"BOOL" => Bool,
"SYMBOL" => Symbol,
"TUPLE" => Tuple,
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
"RGBA" => ARGB{N0f8},
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
#Sub-structure types:
"FONT" => Font,
"BOUNDINGBOX" => BoundingBox,
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SUBPLOT" => Subplot,
"NULLABLE" => Nullable,
)
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
end
end
end
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{HDF5Backend})
@@ -236,15 +222,11 @@ end
# ----------------------------------------------------------------
_show(io::IO, mime::MIME"text/plain", plt::Plot{HDF5Backend}) = nothing #Don't show
# ----------------------------------------------------------------
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{HDF5Backend})
msg = "HDF5 interface does not support `display()` function."
msg *= "\nUse `Plots.hdf5plot_write(::String)` method to write to .HDF5 \"plot\" file instead."
warn(msg)
@warn(msg)
return
end
@@ -276,11 +258,11 @@ function _hdf5plot_overwritetype(grp, T::Type) #Write directly to group
HDF5.a_delete(grp, _hdf5plot_datatypeid)
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype{T<:Any}(grp, ::Type{Array{T}})
function _hdf5plot_writetype(grp, ::Type{Array{T}}) where T<:Any
tstr = HDF5PLOT_MAP_TELEM2STR[Array] #ANY
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype{T<:BoundingBox}(grp, ::Type{T})
function _hdf5plot_writetype(grp, ::Type{T}) where T<:BoundingBox
tstr = HDF5PLOT_MAP_TELEM2STR[BoundingBox]
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
@@ -289,7 +271,7 @@ function _hdf5plot_writecount(grp, n::Int) #Write directly to group
end
function _hdf5plot_gwritefields(grp, k::String, v)
grp = HDF5.g_create(grp, k)
for _k in fieldnames(v)
for _k in fieldnames(typeof(v))
_v = getfield(v, _k)
kstr = string(_k)
_hdf5plot_gwrite(grp, kstr, _v)
@@ -305,19 +287,19 @@ function _hdf5plot_gwrite(grp, k::String, v) #Default
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
function _hdf5plot_gwrite{T<:Number}(grp, k::String, v::Array{T}) #Default for arrays
function _hdf5plot_gwrite(grp, k::String, v::Array{T}) where T<:Number #Default for arrays
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
#=
function _hdf5plot_gwrite(grp, k::String, v::Array{Any})
# @show grp, k
warn("Cannot write Array: $k=$v")
@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)
@@ -342,9 +324,9 @@ function _hdf5plot_gwrite(grp, k::String, v::Tuple)
#NOTE: _hdf5plot_overwritetype overwrites "Array" type with "Tuple".
end
function _hdf5plot_gwrite(grp, k::String, d::Dict)
# warn("Cannot write dict: $k=$d")
# @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})
@@ -355,7 +337,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Colorant)
_hdf5plot_gwrite(grp, k, ARGB{N0f8}(v))
end
#Custom vector (when not using simple numeric type):
function _hdf5plot_gwritearray{T}(grp, k::String, v::Array{T})
function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
if "annotations" == k;
return #Hack. Does not yet support annotations.
end
@@ -363,9 +345,10 @@ function _hdf5plot_gwritearray{T}(grp, k::String, v::Array{T})
vgrp = HDF5.g_create(grp, k)
_hdf5plot_writetype(vgrp, Array) #ANY
sz = size(v)
lidx = LinearIndices(sz)
for iter in eachindex(v)
coord = ind2sub(sz, iter)
coord = lidx[iter]
elem = v[iter]
idxstr = join(coord, "_")
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
@@ -380,7 +363,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Extrema)
grp[k] = [v.emin, v.emax]
_hdf5plot_writetype(grp, k, Extrema)
end
function _hdf5plot_gwrite{T}(grp, k::String, v::Length{T})
function _hdf5plot_gwrite(grp, k::String, v::Length{T}) where T
grp[k] = v.value
_hdf5plot_writetype(grp, k, [HDF5PLOT_MAP_TELEM2STR[Length], string(T)])
end
@@ -404,15 +387,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::_hdf5_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
@@ -480,7 +468,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}
@@ -522,10 +510,11 @@ function _hdf5plot_read(grp, k::String, T::Type{Array}, dtid) #ANY
sz = _hdf5plot_read(grp, "dim")
if [0] == sz; return []; end
sz = tuple(sz...)
result = Array{Any}(sz)
result = Array{Any}(undef, sz)
lidx = LinearIndices(sz)
for iter in eachindex(result)
coord = ind2sub(sz, iter)
coord = lidx[iter]
idxstr = join(coord, "_")
result[iter] = _hdf5plot_read(grp, "v$idxstr")
end
@@ -574,6 +563,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")
@@ -595,7 +589,7 @@ function _hdf5plot_read(grp, d::Dict)
catch e
@show e
@show grp
warn("Could not read field $k")
@warn("Could not read field $k")
end
end
return
+76 -80
View File
@@ -18,7 +18,8 @@ Add in functionality to Plots.jl:
const _inspectdr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
# :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
@@ -27,10 +28,13 @@ const _inspectdr_attr = merge_with_base_supported([
:markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:title, :title_location,
:window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :legend, #:colorbar,
# :marker_z,
# :line_z,
@@ -49,7 +53,7 @@ const _inspectdr_attr = merge_with_base_supported([
])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [
:path, :scatter, :shape #, :steppre, :steppost
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
]
#see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[
@@ -82,24 +86,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
@@ -130,7 +134,7 @@ end
function _inspectdr_getscale(s::Symbol, yaxis::Bool)
#TODO: Support :asinh, :sqrt
kwargs = yaxis? (:tgtmajor=>8, :tgtminor=>2): () #More grid lines on y-axis
kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis
if :log2 == s
return InspectDR.AxisScale(:log2; kwargs...)
elseif :log10 == s
@@ -144,37 +148,23 @@ end
# ---------------------------------------------------------------------------
function add_backend_string(::InspectDRBackend)
"""
if !Plots.is_installed("InspectDR")
Pkg.add("InspectDR")
end
"""
#Glyph used when plotting "Shape"s:
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
mutable struct InspecDRPlotRef
mplot::Union{Nothing, InspectDR.Multiplot}
gui::Union{Nothing, InspectDR.GtkPlot}
end
function _initialize_backend(::InspectDRBackend; kw...)
@eval begin
import InspectDR
export InspectDR
_inspectdr_getmplot(::Any) = nothing
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
#Glyph used when plotting "Shape"s:
const INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
type InspecDRPlotRef
mplot::Union{Void, InspectDR.Multiplot}
gui::Union{Void, InspectDR.GtkPlot}
end
_inspectdr_getmplot(::Any) = nothing
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
_inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed? nothing: gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
end
end
_inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
push!(_initialized_backends, :inspectdr)
# ---------------------------------------------------------------------------
@@ -234,13 +224,17 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
#Don't do anything without a "subplot" object: Will process later.
if nothing == plot; return; end
_vectorize(v) = isa(v, Vector)? v: collect(v) #InspectDR only supports vectors
x = _vectorize(series[:x]); y = _vectorize(series[:y])
_vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x, y = if st == :straightline
straightline_data(series)
else
_vectorize(series[:x]), _vectorize(series[:y])
end
#No support for polar grid... but can still perform polar transformation:
if ispolar(sp)
Θ = x; r = y
x = r.*cos(Θ); y = r.*sin(Θ)
x = r.*cos.(Θ); y = r.*sin.(Θ)
end
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
@@ -260,6 +254,7 @@ For st in :shape:
=#
if st in (:shape,)
x, y = shape_data(series)
nmax = 0
for (i,rng) in enumerate(iter_segments(x, y))
nmax = i
@@ -277,7 +272,7 @@ For st in :shape:
end
end
i = (nmax >= 2? div(nmax, 2): nmax) #Must pick one set of colors for legend
i = (nmax >= 2 ? div(nmax, 2) : nmax) #Must pick one set of colors for legend
if i > 1 #Add dummy waveform for legend entry:
linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
@@ -291,11 +286,11 @@ For st in :shape:
color = linecolor, fillcolor = fillcolor
)
end
elseif st in (:path, :scatter) #, :steppre, :steppost)
elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost)
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth:
_style = (0==linewidth? :none: series[:linestyle])
_style = (0==linewidth ? :none : series[:linestyle])
wfrm = InspectDR.add(plot, x, y, id=series[:label])
wfrm.line = InspectDR.line(
style = _style,
@@ -334,15 +329,18 @@ end
# ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
const gridon = InspectDR.GridRect(vmajor=true, hmajor=true)
const gridoff = InspectDR.GridRect()
const plot = sp.o
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
#No independent control of grid???
strip.grid = sp[:grid]? gridon: gridoff
plot = sp.o
strip = plot.strips[1] #Only 1 strip supported with Plots.jl
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
ygrid_show = yaxis[:grid]
strip.grid = InspectDR.GridRect(
vmajor=xgrid_show, # vminor=xgrid_show,
hmajor=ygrid_show, # hminor=ygrid_show,
)
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(xaxis)
@@ -362,36 +360,35 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
l = plot.layout
l.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l.framedata.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l.framedata.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l.fnttitle = InspectDR.Font(sp[:titlefont].family,
_inspectdr_mapptsize(sp[:titlefont].pointsize),
color = _inspectdr_mapcolor(sp[:foreground_color_title])
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l[:font_title] = InspectDR.Font(sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:titlefontcolor])
)
#Cannot independently control fonts of axes with InspectDR:
l.fntaxlabel = InspectDR.Font(xaxis[:guidefont].family,
_inspectdr_mapptsize(xaxis[:guidefont].pointsize),
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide])
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
)
l.fntticklabel = InspectDR.Font(xaxis[:tickfont].family,
_inspectdr_mapptsize(xaxis[:tickfont].pointsize),
color = _inspectdr_mapcolor(xaxis[:foreground_color_text])
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:tickfontcolor])
)
leg = l.legend
leg.enabled = (sp[:legend] != :none)
#leg.width = 150 #TODO: compute???
leg.font = InspectDR.Font(sp[:legendfont].family,
_inspectdr_mapptsize(sp[:legendfont].pointsize),
color = _inspectdr_mapcolor(sp[:foreground_color_legend])
l[:enable_legend] = (sp[:legend] != :none)
#l[:halloc_legend] = 150 #TODO: compute???
l[:font_legend] = InspectDR.Font(sp[:legendfontfamily],
_inspectdr_mapptsize(sp[:legendfontsize]),
color = _inspectdr_mapcolor(sp[:legendfontcolor])
)
leg.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
end
# called just before updating layout bounding boxes... in case you need to prep
# 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]
@@ -399,7 +396,7 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
#Don't use window_title... probably not what you want.
#mplot.title = plt[:window_title]
end
mplot.frame.fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
resize!(mplot.subplots, length(plt.subplots))
nsubplots = length(plt.subplots)
@@ -421,15 +418,15 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
#Do not yet support absolute plot positionning.
#Just try to make things look more-or less ok:
if nsubplots <= 1
mplot.ncolumns = 1
mplot.layout[:ncolumns] = 1
elseif nsubplots <= 4
mplot.ncolumns = 2
mplot.layout[:ncolumns] = 2
elseif nsubplots <= 6
mplot.ncolumns = 3
mplot.layout[:ncolumns] = 3
elseif nsubplots <= 12
mplot.ncolumns = 4
mplot.layout[:ncolumns] = 4
else
mplot.ncolumns = 5
mplot.layout[:ncolumns] = 5
end
for series in plt.series_list
@@ -446,7 +443,7 @@ function _update_min_padding!(sp::Subplot{InspectDRBackend})
plot = sp.o
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
#Computing plotbounds with 0-BoundingBox returns required padding:
bb = InspectDR.plotbounds(plot.layout, InspectDR.BoundingBox(0,0,0,0))
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
#TODO: possibly zero-out items not in use??
@@ -468,7 +465,7 @@ function _update_plot_object(plt::Plot{InspectDRBackend})
for (i, sp) in enumerate(plt.subplots)
graphbb = _inspectdr_to_pixels(plotarea(sp))
plot = mplot.subplots[i]
plot.plotbb = InspectDR.plotbounds(plot.layout, graphbb)
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
end
gplot = _inspectdr_getgui(plt.o)
@@ -491,7 +488,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))
@@ -508,7 +505,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
# ----------------------------------------------------------------
+280 -96
View File
@@ -4,11 +4,12 @@
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,
@@ -23,7 +24,7 @@ const _pgfplots_attr = merge_with_base_supported([
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar,
:marker_z, #:levels,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
@@ -31,30 +32,17 @@ const _pgfplots_attr = merge_with_base_supported([
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
:framestyle,
:camera,
:contour_labels,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
# --------------------------------------------------------------------------------------
function add_backend_string(::PGFPlotsBackend)
"""
Pkg.add("PGFPlots")
Pkg.build("PGFPlots")
"""
end
function _initialize_backend(::PGFPlotsBackend; kw...)
@eval begin
import PGFPlots
export PGFPlots
end
end
# --------------------------------------------------------------------------------------
const _pgfplots_linestyles = KW(
@@ -79,6 +67,7 @@ const _pgfplots_markers = KW(
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*",
:hline => "-"
)
const _pgfplots_legend_pos = KW(
@@ -86,6 +75,7 @@ const _pgfplots_legend_pos = KW(
:bottomright => "south east",
:topright => "north east",
:topleft => "north west",
:outertopright => "outer north east",
)
@@ -98,7 +88,7 @@ const _pgf_series_extrastyle = KW(
:xsticks => "xcomb",
)
# PGFPlots uses the anchors to define orientations for example to align left
# PGFPlots uses the anchors to define orientations for example to align left
# one needs to use the right edge as anchor
const _pgf_annotation_halign = KW(
:center => "",
@@ -106,6 +96,18 @@ const _pgf_annotation_halign = KW(
:right => "left"
)
const _pgf_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
const _pgf_framestyle_defaults = Dict(:semi => :box)
function pgf_framestyle(style::Symbol)
if style in _pgf_framestyles
return style
else
default_style = get(_pgf_framestyle_defaults, style, :axes)
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
default_style
end
end
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
@@ -121,53 +123,75 @@ function pgf_color(grad::ColorGradient)
end
# Generates a colormap for pgfplots based on a ColorGradient
function pgf_colormap(grad::ColorGradient)
function pgf_colormap(grad::ColorGradient)
join(map(grad.colors) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
end,", ")
end
function pgf_fillstyle(d::KW)
cstr,a = pgf_color(d[:fillcolor])
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)
if fa != nothing
a = fa
end
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(d::KW)
cstr,a = pgf_color(d[:linecolor])
function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
cstr, a = pgf_color(plot_color(color, α))
"""
color = $cstr,
draw opacity=$a,
line width=$(d[:linewidth]),
$(get(_pgfplots_linestyles, d[:linestyle], "solid"))"""
draw opacity = $a,
line width = $linewidth,
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
end
function pgf_marker(d::KW)
shape = d[:markershape]
cstr, a = pgf_color(d[:markercolor])
cstr_stroke, a_stroke = pgf_color(d[:markerstrokecolor])
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(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 * d[:markersize]),
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 = $(d[:markerstrokewidth]),
line width = $(pgf_thickness_scaling(d) * _cycle(d[:markerstrokewidth], i)),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, d[:markerstrokestyle], "solid"))
$(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
# --------------------------------------------------------------------------------------
@@ -175,31 +199,20 @@ end
function pgf_series(sp::Subplot, series::Series)
d = series.d
st = d[:seriestype]
style = []
kw = KW()
push!(style, pgf_linestyle(d))
push!(style, pgf_marker(d))
if d[:fillrange] != nothing || st in (:shape,)
push!(style, pgf_fillstyle(d))
end
# add to legend?
if sp[:legend] != :none && should_add_to_legend(series)
kw[:legendentry] = d[:label]
else
push!(style, "forget plot")
end
series_collection = PGFPlots.Plot[]
# function args
args = if st == :contour
args = if st == :contour
d[:z].surf, d[:x], d[:y]
elseif is3d(st)
d[:x], d[:y], d[:z]
elseif d[:marker_z] != nothing
# If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation
d[:x], d[:y], d[:marker_z]
elseif st == :straightline
straightline_data(series)
elseif st == :shape
shape_data(series)
elseif ispolar(sp)
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
rad2deg.(theta), r
else
d[:x], d[:y]
end
@@ -210,34 +223,131 @@ function pgf_series(sp::Subplot, series::Series)
else
a
end, args)
# for (i,a) in enumerate(args)
# if typeof(a) <: AbstractVector && typeof(a) != Vector
# args[i] = collect(a)
# end
# end
# include additional style, then add to the kw
if st in (:contour, :histogram2d)
style = []
kw = KW()
push!(style, pgf_linestyle(d))
push!(style, pgf_marker(d))
push!(style, "forget plot")
kw[:style] = join(style, ',')
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...))
else
# series segments
segments = iter_segments(series)
for (i, rng) in enumerate(segments)
style = []
kw = KW()
push!(style, pgf_linestyle(d, i))
push!(style, pgf_marker(d, i))
if st == :shape
push!(style, pgf_fillstyle(d, i))
end
# add to legend?
if i == 1 && sp[:legend] != :none && should_add_to_legend(series)
if d[:fillrange] != nothing
push!(style, "forget plot")
push!(series_collection, pgf_fill_legend_hack(d, args))
else
kw[:legendentry] = d[:label]
if st == :shape # || d[:fillrange] != nothing
push!(style, "area legend")
end
end
else
push!(style, "forget plot")
end
seg_args = (arg[rng] for arg in args)
# include additional style, then add to the kw
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
end
kw[:style] = join(style, ',')
# add fillrange
if series[:fillrange] != nothing && st != :shape
push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...))
end
# build/return the series object
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
PGFPlots.Scatter
else
PGFPlots.Linear
end
push!(series_collection, func(seg_args...; kw...))
end
end
series_collection
end
function pgf_fillrange_series(series, i, fillrange, args...)
st = series[:seriestype]
style = []
kw = KW()
push!(style, "line width = 0")
push!(style, "draw opacity = 0")
push!(style, pgf_fillstyle(series, i))
push!(style, pgf_marker(series, i))
push!(style, "forget plot")
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
end
kw[:style] = join(style, ',')
func = is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear
return func(pgf_fillrange_args(fillrange, args...)...; kw...)
end
# build/return the series object
function pgf_fillrange_args(fillrange, x, y)
n = length(x)
x_fill = [x; x[n:-1:1]; x[1]]
y_fill = [y; _cycle(fillrange, n:-1:1); y[1]]
return x_fill, y_fill
end
function pgf_fillrange_args(fillrange, x, y, z)
n = length(x)
x_fill = [x; x[n:-1:1]; x[1]]
y_fill = [y; y[n:-1:1]; x[1]]
z_fill = [z; _cycle(fillrange, n:-1:1); z[1]]
return x_fill, y_fill, z_fill
end
function pgf_fill_legend_hack(d, args)
style = []
kw = KW()
push!(style, pgf_linestyle(d, 1))
push!(style, pgf_marker(d, 1))
push!(style, pgf_fillstyle(d, 1))
push!(style, "area legend")
kw[:legendentry] = d[:label]
kw[:style] = join(style, ',')
st = d[:seriestype]
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
PGFPlots.Scatter
elseif st == :histogram2d
PGFPlots.Histogram2
elseif st == :contour
PGFPlots.Contour
else
PGFPlots.Linear
end
func(args...; kw...)
return func(([arg[1]] for arg in args)...; kw...)
end
# ----------------------------------------------------------------
function pgf_axis(sp::Subplot, letter)
@@ -245,11 +355,18 @@ function pgf_axis(sp::Subplot, letter)
style = []
kw = KW()
# turn off scaled ticks
push!(style, "scaled $(letter) ticks = false")
# set to supported framestyle
framestyle = pgf_framestyle(sp[:framestyle])
# 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")
@@ -262,22 +379,75 @@ function pgf_axis(sp::Subplot, letter)
end
# ticks on or off
if axis[:ticks] in (nothing, false)
if axis[:ticks] in (nothing, false, :none) || framestyle == :none
push!(style, "$(letter)majorticks=false")
end
# grid on or off
if axis[:grid] && framestyle != :none
push!(style, "$(letter)majorgrids = true")
else
push!(style, "$(letter)majorgrids = false")
end
# limits
# TODO: support zlims
if letter != :z
lims = axis_limits(axis)
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :auto))
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
ticks = get_ticks(axis)
push!(style, string(letter, "tick = {", join(ticks[1],","), "}"))
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}"))
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = Vector{String}(length(ticks[2]))
for (i, label) in enumerate(ticks[2])
base, power = split(label, "^")
power = string("{", power, "}")
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]
if axis[:formatter] in (:scientific, :auto)
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
tick_labels = replace.(tick_labels, "×", "\\times")
end
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
else
push!(style, string(letter, "ticklabels = {}"))
end
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
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
if framestyle in (:axes, :origin)
axispos = framestyle == :axes ? "left" : "middle"
# the * after lines disables the arrows at the axes
push!(style, string("axis lines* = ", axispos))
end
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
end
if !axis[:showaxis]
push!(style, "separate axis lines")
end
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
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
@@ -314,7 +484,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"
@@ -322,9 +492,10 @@ 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
sp[:grid] && push!(style, "grid = major")
if sp[:aspect_ratio] in (1, :equal)
kw[:axisEqual] = "true"
end
@@ -333,10 +504,23 @@ 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 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
axisf = PGFPlots.Axis
if sp[:projection] == :polar
axisf = PGFPlots.PolarAxis
#make radial axis vertical
kw[:xmin] = 90
kw[:xmax] = 450
end
# Search series for any gradient. In case one series uses a gradient set
@@ -350,7 +534,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# As it is likely that all series within the same axis use the same
# colormap this should not cause any problem.
for series in series_list(sp)
for col in (:markercolor, :fillcolor)
for col in (:markercolor, :fillcolor, :linecolor)
if typeof(series.d[col]) == ColorGradient
push!(style,"colormap={plots}{$(pgf_colormap(series.d[col]))}")
@@ -360,28 +544,28 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:colorbar] = "true"
end
# goto is needed to break out of col and series for
@goto colorbar_end
@goto colorbar_end
end
end
end
@label colorbar_end
o = axisf(; style = style, kw...)
o = axisf(; style = join(style, ","), kw...)
# add the series object to the PGFPlots.Axis
for series in series_list(sp)
push!(o, pgf_series(sp, series))
push!.(o, pgf_series(sp, series))
# 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,ann...)
pgf_add_annotation!(o, locate_annotation(sp, ann...)..., pgf_thickness_scaling(sp))
end
@@ -403,7 +587,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)
@@ -412,7 +596,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})
+420 -192
View File
@@ -5,7 +5,7 @@ const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
# :foreground_color_grid, :foreground_color_axis,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
@@ -15,12 +15,18 @@ const _plotly_attr = merge_with_base_supported([
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
:title, :title_location, :titlefont,
:title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :levels,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :line_z, :levels,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
@@ -32,11 +38,16 @@ const _plotly_attr = merge_with_base_supported([
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _plotly_seriestype = [
:path, :scatter, :bar, :pie, :heatmap,
:path, :scatter, :pie, :heatmap,
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
:straightline
]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [
@@ -46,52 +57,52 @@ const _plotly_marker = [
const _plotly_scale = [:identity, :log10]
is_subplot_supported(::PlotlyBackend) = true
# is_string_supported(::PlotlyBackend) = true
const _plotly_framestyles = [:box, :axes, :zerolines, :grid, :none]
const _plotly_framestyle_defaults = Dict(:semi => :box, :origin => :zerolines)
function _plotly_framestyle(style::Symbol)
if style in _plotly_framestyles
return style
else
default_style = get(_plotly_framestyle_defaults, style, :axes)
@warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
default_style
end
end
# --------------------------------------------------------------------------------------
function add_backend_string(::PlotlyBackend)
"""
Pkg.build("Plots")
"""
end
const _plotly_js_path = joinpath(dirname(@__FILE__), "..", "..", "deps", "plotly-latest.min.js")
const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
function _initialize_backend(::PlotlyBackend; kw...)
@eval begin
import JSON
_js_code = open(read, _plotly_js_path, "r")
_js_code = open(readstring, _plotly_js_path, "r")
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
_js_script = """
<script type='text/javascript'>
define('plotly', function(require, exports, module) {
$(_js_code)
});
require(['plotly'], function(Plotly) {
window.Plotly = Plotly;
});
</script>
"""
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
_js_script = """
<script type='text/javascript'>
define('plotly', function(require, exports, module) {
$(_js_code)
});
require(['plotly'], function(Plotly) {
window.Plotly = Plotly;
});
</script>
"""
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
display("text/html", _js_script)
end
# if isatom()
# import Atom
# Atom.@msg evaljs(_js_code)
# end
end
# TODO: other initialization
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
display("text/html", _js_script)
end
# if isatom()
# import Atom
# Atom.@msg evaljs(_js_code)
# end
using UUIDs
push!(_initialized_backends, :plotly)
# ----------------------------------------------------------------
@@ -107,7 +118,7 @@ const _plotly_legend_pos = KW(
)
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
plotly_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T}) = v
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
function plotly_font(font::Font, color = font.color)
KW(
@@ -123,7 +134,7 @@ function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
:text => val,
:xref => xref,
:x => x,
:yref => xref,
:yref => yref,
:y => y,
:showarrow => false,
)
@@ -209,43 +220,57 @@ function plotly_domain(sp::Subplot, letter)
end
function plotly_axis(axis::Axis, sp::Subplot)
function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
letter = axis[:letter]
framestyle = sp[:framestyle]
ax = KW(
:visible => framestyle != :none,
:title => axis[:guide],
:showgrid => sp[:grid],
:zeroline => false,
:ticks => "inside",
:showgrid => axis[:grid],
:gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
:gridwidth => axis[:gridlinewidth],
:zeroline => framestyle == :zerolines,
:zerolinecolor => rgba_string(axis[:foreground_color_axis]),
:showline => framestyle in (:box, :axes) && axis[:showaxis],
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks => axis[:tick_direction] == :out ? "outside" : "inside",
:mirror => framestyle == :box,
:showticklabels => axis[:showaxis],
)
if letter in (:x,:y)
ax[:domain] = plotly_domain(sp, letter)
ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))"
if is3d(sp)
# don't link 3d axes for synchronized interactivity
x_idx = y_idx = sp[:subplot_index]
else
x_idx, y_idx = plotly_link_indicies(plt, sp)
end
ax[:anchor] = "$(letter==:x ? "y$(y_idx)" : "x$(x_idx)")"
end
ax[:tickangle] = -axis[:rotation]
ax[:type] = plotly_scale(axis[:scale])
lims = axis_limits(axis)
if !(axis[:ticks] in (nothing, :none))
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
ax[:tickcolor] = rgba_string(axis[:foreground_color_border])
ax[:linecolor] = rgba_string(axis[:foreground_color_border])
if axis[:ticks] != :native || axis[:lims] != :auto
ax[:range] = map(scalefunc(axis[:scale]), lims)
end
# lims
lims = axis[:lims]
if lims != :auto && limsType(lims) == :limits
ax[:range] = map(scalefunc(axis[:scale]), lims)
end
if !(axis[:ticks] in (nothing, :none, false))
ax[:titlefont] = plotly_font(guidefont(axis))
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
ticks = get_ticks(axis)
if ticks != :auto
if axis[:ticks] != :native
ticks = get_ticks(axis)
ttype = ticksType(ticks)
if ttype == :ticks
ax[:tickmode] = "array"
@@ -260,6 +285,23 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:showgrid] = false
end
ax
end
function plotly_polaraxis(axis::Axis)
ax = KW(
:visible => axis[:showaxis],
:showline => axis[:grid],
)
if axis[:letter] == :x
ax[:range] = rad2deg.(axis_limits(axis))
else
ax[:range] = axis_limits(axis)
ax[:orientation] = -90
end
ax
end
@@ -273,10 +315,11 @@ function plotly_layout(plt::Plot)
d_out[:annotations] = KW[]
multiple_subplots = length(plt.subplots) > 1
for sp in plt.subplots
spidx = plotly_subplot_index(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] != ""
@@ -290,22 +333,40 @@ function plotly_layout(plt::Plot)
0.5 * (left(bb) + right(bb))
end
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
titlefont = font(sp[:titlefont], :top, sp[:foreground_color_title])
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont)))
title_font = font(titlefont(sp), :top)
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
end
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
# set to supported framestyle
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
# if any(is3d, seriesargs)
if is3d(sp)
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
d_out[:scene] = KW(
Symbol("xaxis$spidx") => plotly_axis(sp[:xaxis], sp),
Symbol("yaxis$spidx") => plotly_axis(sp[:yaxis], sp),
Symbol("zaxis$spidx") => plotly_axis(sp[:zaxis], sp),
Symbol("xaxis$(spidx)") => plotly_axis(plt, sp[:xaxis], sp),
Symbol("yaxis$(spidx)") => plotly_axis(plt, sp[:yaxis], sp),
Symbol("zaxis$(spidx)") => plotly_axis(plt, sp[:zaxis], sp),
#2.6 multiplier set camera eye such that whole plot can be seen
:camera => KW(
:eye => KW(
:x => cosd(azim)*sind(theta)*2.6,
:y => sind(azim)*sind(theta)*2.6,
:z => cosd(theta)*2.6,
),
),
)
elseif ispolar(sp)
d_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
d_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
else
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
d_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
# don't allow yaxis to be reupdated/reanchored in a linked subplot
spidx == y_idx ? d_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing
end
# legend
@@ -315,15 +376,17 @@ function plotly_layout(plt::Plot)
d_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]),
:font => plotly_font(legendfont(sp)),
:tracegroupgap => 0,
:x => xpos,
:y => ypos
)
end
# annotations
append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]])
for ann in sp[:annotations]
append!(d_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
end
# series_annotations
for series in series_list(sp)
anns = series[:series_annotations]
@@ -331,7 +394,7 @@ function plotly_layout(plt::Plot)
push!(d_out[:annotations], plotly_annotation_dict(
xi,
yi,
PlotText(str,fnt); xref = "x$spidx", yref = "y$spidx")
PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)")
)
end
end
@@ -367,9 +430,17 @@ end
function plotly_colorscale(grad::ColorGradient, α)
[[grad.values[i], rgb_string(grad.colors[i])] for i in 1:length(grad.colors)]
[[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in 1:length(grad.colors)]
end
plotly_colorscale(c, α) = plotly_colorscale(cgrad(alpha=α), α)
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 = 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
# plotly_colorscale(c, alpha = nothing) = plotly_colorscale(cgrad(), alpha)
@@ -384,9 +455,15 @@ const _plotly_markers = KW(
:hline => "line-ew",
)
function plotly_subplot_index(sp::Subplot)
spidx = sp[:subplot_index]
spidx == 1 ? "" : spidx
# find indicies of axes to which the supblot links to
function plotly_link_indicies(plt::Plot, sp::Subplot)
if plt[:link] in (:x, :y, :both)
x_idx = sp[:xaxis].sps[1][:subplot_index]
y_idx = sp[:yaxis].sps[1][:subplot_index]
else
x_idx = y_idx = sp[:subplot_index]
end
x_idx, y_idx
end
@@ -401,14 +478,51 @@ function plotly_close_shapes(x, y)
nanvcat(xs), nanvcat(ys)
end
plotly_data(v) = collect(v)
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{R<:Rational}(v::AbstractArray{R}) = float(v)
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
plotly_surface_data(series::Series, a::AbstractVector) = a
plotly_surface_data(series::Series, a::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 = α)
@@ -424,24 +538,29 @@ function plotly_series(plt::Plot, series::Series)
d_out = KW()
# these are the axes that the series should be mapped to
spidx = plotly_subplot_index(sp)
d_out[:xaxis] = "x$spidx"
d_out[:yaxis] = "y$spidx"
x_idx, y_idx = plotly_link_indicies(plt, sp)
d_out[:xaxis] = "x$(x_idx)"
d_out[:yaxis] = "y$(y_idx)"
d_out[:showlegend] = should_add_to_legend(series)
x, y = plotly_data(series[:x]), plotly_data(series[:y])
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)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d)
# for surface types, set the data
if st in (:heatmap, :contour, :surface, :wireframe)
for letter in [:x,:y,:z]
d_out[letter] = plotly_surface_data(series, series[letter])
end
end
hasline = st in (:path, :path3d, :straightline)
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
d_out[:colorbar] = KW(:title => sp[:colorbar_title])
@@ -451,59 +570,45 @@ function plotly_series(plt::Plot, series::Series)
end
# set the "type"
if st in (:path, :scatter, :scattergl)
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
if series[:fillrange] == true || series[:fillrange] == 0
d_out[:fill] = "tozeroy"
d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif !(series[:fillrange] in (false, nothing))
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(series[:fillrange])")
end
d_out[:x], d_out[:y] = x, y
elseif st == :bar
d_out[:type] = "bar"
d_out[:x], d_out[:y], d_out[:orientation] = if isvertical(series)
x, y, "v"
else
y, x, "h"
end
d_out[:marker] = KW(:color => rgba_string(series[:fillcolor]))
if st in (:path, :scatter, :scattergl, :straightline, :path3d, :scatter3d)
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] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:x], d_out[:y], d_out[:z] = x, y, z
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:showscale] = hascolorbar(sp)
elseif st == :contour
d_out[:type] = "contour"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:x], d_out[:y], d_out[:z] = x, y, z
# d_out[:showscale] = series[:colorbar] != :none
d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
d_out[:showscale] = hascolorbar(sp)
elseif st in (:surface, :wireframe)
d_out[:type] = "surface"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:x], d_out[:y], d_out[:z] = x, y, z
if st == :wireframe
d_out[:hidesurface] = true
wirelines = KW(
:show => true,
:color => rgba_string(series[:linecolor]),
:color => rgba_string(plot_color(series[:linecolor], series[:linealpha])),
:highlightwidth => series[:linewidth],
)
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
d_out[:showscale] = false
else
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:opacity] = series[:fillalpha]
if series[:fill_z] != nothing
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
end
d_out[:showscale] = hascolorbar(sp)
end
elseif st == :pie
@@ -512,116 +617,242 @@ function plotly_series(plt::Plot, series::Series)
d_out[:values] = y
d_out[:hoverinfo] = "label+percent+name"
elseif st in (:path3d, :scatter3d)
d_out[:type] = "scatter3d"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
d_out[:x], d_out[:y] = x, y
d_out[:z] = plotly_data(series[:z])
else
warn("Plotly: seriestype $st isn't supported.")
@warn("Plotly: seriestype $st isn't supported.")
return KW()
end
# 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 => rgba_string(series[:markerstrokecolor]),
: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
d_out[:marker][:color] = if series[:marker_z] == nothing
rgba_string(series[:markercolor])
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
grad = as_gradient(series[:markercolor], series[:markeralpha])
zmin, zmax = ignorenan_extrema(series[:marker_z])
zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
[rgba_string(grad[(zi - zmin) / zrange]) for zi in series[:marker_z]]
end
end
# add "line"
if hasline
d_out[:line] = KW(
:color => rgba_string(series[:linecolor]),
:width => series[:linewidth],
:shape => if st == :steppre
"vh"
elseif st == :steppost
"hv"
else
"linear"
end,
:dash => string(series[:linestyle]),
# :dash => "solid",
)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, series[:hover])
[d_out]
return [d_out]
end
function plotly_series_shapes(plt::Plot, series::Series)
d_outs = []
segments = iter_segments(series)
d_outs = Vector{KW}(undef, length(segments))
# TODO: create a d_out for each polygon
# x, y = series[:x], series[:y]
# these are the axes that the series should be mapped to
spidx = plotly_subplot_index(series[:subplot])
base_d = KW()
base_d[:xaxis] = "x$spidx"
base_d[:yaxis] = "y$spidx"
base_d[:name] = series[:label]
# base_d[:legendgroup] = series[:label]
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
d_base = KW(
:xaxis => "x$(x_idx)",
:yaxis => "y$(y_idx)",
:name => series[:label],
:legendgroup => series[:label],
)
x, y = plotly_data(series[:x]), plotly_data(series[:y])
for (i,rng) in enumerate(iter_segments(x,y))
x, y = (plotly_data(series, letter, data)
for (letter, data) in zip((: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]]),
:y => vcat(y[rng], y[rng[1]]),
:fill => "tozeroy",
:fillcolor => rgba_string(_cycle(series[:fillcolor], i)),
:fillcolor => rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i))),
))
if series[:markerstrokewidth] > 0
d_out[:line] = KW(
:color => rgba_string(_cycle(series[:linecolor], i)),
:width => series[:linewidth],
:dash => string(series[:linestyle]),
:color => rgba_string(plot_color(get_linecolor(series, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:dash => string(get_linestyle(series, i)),
)
end
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotly_polar!(d_out, series)
plotly_hover!(d_out, _cycle(series[:hover], i))
push!(d_outs, d_out)
d_outs[i] = d_out
end
if series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
elseif series[:line_z] != nothing
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
function plotly_series_segments(series::Series, d_base::KW, x, y, z)
st = series[:seriestype]
sp = series[:subplot]
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d, :straightline)
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
segments = iter_segments(series)
d_outs = Vector{KW}(undef, (hasfillrange ? 2 : 1 ) * length(segments))
for (i,rng) in enumerate(segments)
!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)
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
d_out[:fill] = "tozeroy"
d_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i)))
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
d_out[:fill] = "tonexty"
d_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i)))
elseif !(series[:fillrange] in (false, nothing))
@warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
end
d_out[:x], d_out[:y] = x[rng], y[rng]
elseif st in (:path3d, :scatter3d)
d_out[:type] = "scatter3d"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
d_out[:x], d_out[:y], d_out[:z] = x[rng], y[rng], z[rng]
end
# add "marker"
if hasmarker
d_out[:marker] = KW(
:symbol => get(_plotly_markers, _cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
# :opacity => series[:markeralpha],
:size => 2 * _cycle(series[:markersize], i),
:color => rgba_string(plot_color(get_markercolor(series, i), get_markeralpha(series, i))),
:line => KW(
:color => rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))),
:width => _cycle(series[:markerstrokewidth], i),
),
)
end
# add "line"
if hasline
d_out[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:shape => if st == :steppre
"vh"
elseif st == :steppost
"hv"
else
"linear"
end,
:dash => string(get_linestyle(series, i)),
)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, _cycle(series[:hover], rng))
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
# series, one for series being filled to) instead of one
d_out_fillrange = deepcopy(d_out)
d_out_fillrange[:showlegend] = false
# if fillrange is provided as real or tuple of real, expand to array
if typeof(series[:fillrange]) <: Real
series[:fillrange] = fill(series[:fillrange], length(rng))
elseif typeof(series[:fillrange]) <: Tuple
f1 = typeof(series[:fillrange][1]) <: Real ? fill(series[:fillrange][1], length(rng)) : series[:fillrange][1][rng]
f2 = typeof(series[:fillrange][2]) <: Real ? fill(series[:fillrange][2], length(rng)) : series[:fillrange][2][rng]
series[:fillrange] = (f1, f2)
end
if isa(series[:fillrange], AbstractVector)
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
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)
end
d_outs[(2 * i - 1):(2 * i)] = [d_out_fillrange, d_out]
else
d_outs[i] = d_out
end
end
if series[:line_z] != nothing
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
end
function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
d_out = deepcopy(d_base)
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)
d_out[:z] = [series[:z][1]]
end
# 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,
:colorscale => plotly_colorscale(series[Symbol("$(sym)color")], 1),
:showscale => hascolorbar(series[:subplot]),
)
return d_out
end
function plotly_polar!(d_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(series[:subplot])
d_out[:t] = rad2deg(pop!(d_out, :x))
d_out[:r] = pop!(d_out, :y)
theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
d_out[:t] = rad2deg.(theta)
d_out[:r] = r
end
end
@@ -636,21 +867,23 @@ function plotly_hover!(d_out::KW, hover)
end
# get a list of dictionaries, each representing the series params
function plotly_series_json(plt::Plot)
function plotly_series(plt::Plot)
slist = []
for series in plt.series_list
append!(slist, plotly_series(plt, series))
end
JSON.json(slist)
# JSON.json(map(series -> plotly_series(plt, series), plt.series_list))
slist
end
# get json string for a list of dictionaries, each representing the series params
plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt))
# ----------------------------------------------------------------
const _use_remote = Ref(false)
function html_head(plt::Plot{PlotlyBackend})
jsfilename = _use_remote[] ? _plotly_js_path_remote : _plotly_js_path
jsfilename = _use_remote[] ? _plotly_js_path_remote : ("file://" * _plotly_js_path)
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
"<script src=\"$jsfilename\"></script>"
end
@@ -660,7 +893,7 @@ function html_body(plt::Plot{PlotlyBackend}, style = nothing)
w, h = plt[:size]
style = "width:$(w)px;height:$(h)px;"
end
uuid = Base.Random.uuid4()
uuid = UUIDs.uuid4()
html = """
<div id=\"$(uuid)\" style=\"$(style)\"></div>
<script>
@@ -682,12 +915,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})
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, html_head(plt) * html_body(plt))
end
+9 -31
View File
@@ -10,35 +10,6 @@ const _plotlyjs_scale = _plotly_scale
# --------------------------------------------------------------------------------------
function add_backend_string(::PlotlyJSBackend)
"""
if !Plots.is_installed("PlotlyJS")
Pkg.add("PlotlyJS")
end
if !Plots.is_installed("Rsvg")
Pkg.add("Rsvg")
end
import Blink
Blink.AtomShell.install()
"""
end
function _initialize_backend(::PlotlyJSBackend; kw...)
@eval begin
import PlotlyJS
export PlotlyJS
end
# # override IJulia inline display
# if isijulia()
# IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
# end
end
# ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
@@ -67,7 +38,7 @@ function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
end
PlotlyJS.restyle!(
plt.o,
findfirst(plt.series_list, series),
findfirst(isequal(series), plt.series_list),
kw
)
end
@@ -85,7 +56,7 @@ end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else
@@ -98,6 +69,7 @@ function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
@@ -116,6 +88,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)
+358 -279
View File
File diff suppressed because it is too large Load Diff
+3 -8
View File
@@ -3,14 +3,9 @@
# [ADD BACKEND WEBSITE]
function _initialize_backend(::[PkgName]Backend; kw...)
@eval begin
import [PkgName]
export [PkgName]
# todo: other initialization that needs to be eval-ed
end
# todo: other initialization
end
import [PkgName]
export [PkgName]
push!(_initialized_backends, [pgkname]::Symbol)
# ---------------------------------------------------------------------------
+12 -22
View File
@@ -13,7 +13,7 @@ const _unicodeplots_attr = merge_with_base_supported([
:guide, :lims,
])
const _unicodeplots_seriestype = [
:path, :scatter,
:path, :scatter, :straightline,
# :bar,
:shape,
:histogram2d,
@@ -29,22 +29,6 @@ warnOnUnsupported_args(::UnicodePlotsBackend, d::KW) = nothing
# --------------------------------------------------------------------------------------
function add_backend_string(::UnicodePlotsBackend)
"""
Pkg.add("UnicodePlots")
Pkg.build("UnicodePlots")
"""
end
function _initialize_backend(::UnicodePlotsBackend; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
end
# -------------------------------
const _canvas_type = Ref(:auto)
function _canvas_map()
@@ -138,7 +122,7 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
return
end
if st == :path
if st in (:path, :straightline)
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
@@ -151,14 +135,20 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
end
# get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
x, y = if st == :straightline
straightline_data(d)
elseif st == :shape
shape_data(series)
else
[collect(float(d[s])) for s in (:x, :y)]
end
label = addlegend ? d[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
# add the series
x, y = Plots.unzip(collect(filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
x, y = Plots.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
func(o, x, y; color = color, name = label)
end
@@ -173,7 +163,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
@@ -202,7 +192,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
+5 -5
View File
@@ -3,13 +3,13 @@
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
"""
<!DOCTYPE html>
<html>
<head>
<title>$title</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
$(html_head(plt))
</head>
<body>
@@ -20,16 +20,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)
+151 -47
View File
@@ -7,11 +7,11 @@ nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : angle)
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
# -------------------------------------------------------------
immutable Shape
struct Shape
x::Vector{Float64}
y::Vector{Float64}
# function Shape(x::AVec, y::AVec)
@@ -22,6 +22,13 @@ immutable Shape
# end
# end
end
"""
Shape(x, y)
Shape(vertices)
Construct a polygon to be plotted
"""
Shape(verts::AVec) = Shape(unzip(verts)...)
Shape(s::Shape) = deepcopy(s)
@@ -32,6 +39,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
#deprecated
@deprecate shape_coords coords
"return the vertex points from a Shape or Segments object"
function coords(shape::Shape)
shape.x, shape.y
end
@@ -50,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)"
@@ -60,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)
@@ -156,6 +165,7 @@ Shape(k::Symbol) = deepcopy(_shapes[k])
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
"return the centroid of a Shape"
function center(shape::Shape)
x, y = coords(shape)
n = length(x)
@@ -189,6 +199,7 @@ function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
scale!(shapecopy, x, y, c)
end
"translate a Shape in space"
function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape)
for i=1:length(sx)
@@ -227,6 +238,7 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
shape
end
"rotate an object in space"
function rotate(shape::Shape, Θ::Real, c = center(shape))
shapecopy = deepcopy(shape)
rotate!(shapecopy, Θ, c)
@@ -235,7 +247,7 @@ end
# -----------------------------------------------------------------------
type Font
mutable struct Font
family::AbstractString
pointsize::Int
halign::Symbol
@@ -285,7 +297,7 @@ function font(args...)
elseif typeof(arg) <: Real
rotation = convert(Float64, arg)
else
warn("Unused font arg: $arg ($(typeof(arg)))")
@warn("Unused font arg: $arg ($(typeof(arg)))")
end
end
@@ -294,23 +306,50 @@ end
function scalefontsize(k::Symbol, factor::Number)
f = default(k)
f.pointsize = round(Int, factor * f.pointsize)
f = round(Int, factor * f)
default(k, f)
end
"""
scalefontsizes(factor::Number)
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
"""
function scalefontsizes(factor::Number)
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
for k in (:titlefontsize, :guidefontsize, :tickfontsize, :legendfontsize)
scalefontsize(k, factor)
end
end
"""
scalefontsizes()
Resets font sizes to initial default values.
"""
function scalefontsizes()
for k in (:titlefontsize, :guidefontsize, :tickfontsize, :legendfontsize)
f = default(k)
if k in keys(_initial_fontsizes)
factor = f / _initial_fontsizes[k]
scalefontsize(k, 1.0/factor)
end
end
end
"Wrap a string with font info"
immutable PlotText
struct PlotText
str::AbstractString
font::Font
end
PlotText(str) = PlotText(string(str), font())
"""
text(string, args...)
Create a PlotText object wrapping a string with font info, for plot annotations
"""
text(t::PlotText) = t
text(t::PlotText, font::Font) = PlotText(t.str, font)
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
PlotText(string(str), font(args...))
@@ -322,13 +361,18 @@ Base.length(t::PlotText) = length(t.str)
# -----------------------------------------------------------------------
immutable Stroke
struct Stroke
width
color
alpha
style
end
"""
stroke(args...; alpha = nothing)
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing)
width = 1
color = :black
@@ -345,13 +389,14 @@ function stroke(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
width = arg
else
warn("Unused stroke arg: $arg ($(typeof(arg)))")
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
end
end
@@ -359,7 +404,7 @@ function stroke(args...; alpha = nothing)
end
immutable Brush
struct Brush
size # fillrange, markersize, or any other sizey attribute
color
alpha
@@ -377,13 +422,14 @@ function brush(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
size = arg
else
warn("Unused brush arg: $arg ($(typeof(arg)))")
@warn("Unused brush arg: $arg ($(typeof(arg)))")
end
end
@@ -392,19 +438,19 @@ end
# -----------------------------------------------------------------------
type SeriesAnnotations
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)
@@ -414,7 +460,7 @@ function series_annotations(strs::AbstractVector, args...)
elseif is_2tuple(arg)
scalefactor = arg
else
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
end
end
# if scalefactor != 1
@@ -425,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]
@@ -440,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)
@@ -463,22 +510,25 @@ 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
return
end
type EachAnn
mutable struct EachAnn
anns
x
y
end
Base.start(ea::EachAnn) = 1
Base.done(ea::EachAnn, i) = ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
function Base.next(ea::EachAnn, i)
function Base.iterate(ea::EachAnn, i = 1)
if ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
return nothing
end
tmp = _cycle(ea.anns.strs,i)
str,fnt = if isa(tmp, PlotText)
tmp.str, tmp.font
@@ -488,20 +538,68 @@ 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
# Expand arrays of coordinates, positions and labels into induvidual annotations
# and make sure labels are of type PlotText
function process_annotation(sp::Subplot, xs, ys, labs, font = font())
anns = []
labs = makevec(labs)
for i in 1:max(length(xs), length(ys), length(labs))
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (x, y, isa(lab, PlotText) ? lab : text(lab, font)))
end
end
anns
end
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font())
anns = []
positions, labs = makevec(positions), makevec(labs)
for i in 1:max(length(positions), length(labs))
pos, lab = _cycle(positions, i), _cycle(labs, i)
pos = get(_positionAliases, pos, pos)
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font)))
end
end
anns
end
# Give each annotation coordinates based on specified position
function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}(
:topleft => (0.1, 0.9),
:topcenter => (0.5, 0.9),
:topright => (0.9, 0.9),
:bottomleft => (0.1, 0.1),
:bottomcenter => (0.5, 0.1),
:bottomright => (0.9, 0.1),
)
xmin, xmax = ignorenan_extrema(sp[:xaxis])
ymin, ymax = ignorenan_extrema(sp[:yaxis])
x, y = (xmin, ymin).+ position_multiplier[pos].* (xmax - xmin, ymax - ymin)
(x, y, lab)
end
locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label)
# -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)"
immutable ZValues
struct ZValues
values::Vector{Float64}
zrange::Tuple{Float64,Float64}
end
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values)))
function zvalues(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values))) where T<:Real
ZValues(collect(float(values)), map(Float64, zrange))
end
@@ -510,7 +608,7 @@ end
abstract type AbstractSurface end
"represents a contour or surface mesh"
immutable Surface{M<:AMat} <: AbstractSurface
struct Surface{M<:AMat} <: AbstractSurface
surf::M
end
@@ -522,7 +620,7 @@ for f in (:length, :size)
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
end
Base.copy(surf::Surface) = Surface(copy(surf.surf))
Base.eltype{T}(surf::Surface{T}) = eltype(T)
Base.eltype(surf::Surface{T}) where {T} = eltype(T)
function expand_extrema!(a::Axis, surf::Surface)
ex = a[:extrema]
@@ -533,7 +631,7 @@ function expand_extrema!(a::Axis, surf::Surface)
end
"For the case of representing a surface as a function of x/y... can possibly avoid allocations."
immutable SurfaceFunction <: AbstractSurface
struct SurfaceFunction <: AbstractSurface
f::Function
end
@@ -543,19 +641,19 @@ end
# # I don't want to clash with ValidatedNumerics, but this would be nice:
# ..(a::T, b::T) = (a,b)
immutable Volume{T}
struct Volume{T}
v::Array{T,3}
x_extents::Tuple{T,T}
y_extents::Tuple{T,T}
z_extents::Tuple{T,T}
end
default_extents{T}(::Type{T}) = (zero(T), one(T))
default_extents(::Type{T}) where {T} = (zero(T), one(T))
function Volume{T}(v::Array{T,3},
x_extents = default_extents(T),
y_extents = default_extents(T),
z_extents = default_extents(T))
function Volume(v::Array{T,3},
x_extents = default_extents(T),
y_extents = default_extents(T),
z_extents = default_extents(T)) where T
Volume(v, x_extents, y_extents, z_extents)
end
@@ -563,19 +661,25 @@ Base.Array(vol::Volume) = vol.v
for f in (:length, :size)
@eval Base.$f(vol::Volume, args...) = $f(vol.v, args...)
end
Base.copy{T}(vol::Volume{T}) = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
Base.eltype{T}(vol::Volume{T}) = T
Base.copy(vol::Volume{T}) where {T} = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
Base.eltype(vol::Volume{T}) where {T} = T
# -----------------------------------------------------------------------
# style is :open or :closed (for now)
immutable Arrow
struct Arrow
style::Symbol
side::Symbol # :head (default), :tail, or :both
headlength::Float64
headwidth::Float64
end
"""
arrow(args...)
Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
`side` (`:head`, `:tail` or `:both`), `headlength` and `headwidth`
"""
function arrow(args...)
style = :simple
side = :head
@@ -600,7 +704,7 @@ function arrow(args...)
elseif T <: Tuple && length(arg) == 2
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
else
warn("Skipped arrow arg $arg")
@warn("Skipped arrow arg $arg")
end
end
Arrow(style, side, headlength, headwidth)
@@ -625,14 +729,14 @@ end
# -----------------------------------------------------------------------
"Represents data values with formatting that should apply to the tick labels."
immutable Formatted{T}
struct Formatted{T}
data::T
formatter::Function
end
# -----------------------------------------------------------------------
type BezierCurve{T <: FixedSizeArrays.Vec}
"create a BezierCurve for plotting"
mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T}
end
@@ -650,7 +754,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})
+8 -8
View File
@@ -197,7 +197,7 @@ function getGadflyMarkerTheme(d::KW, attr::KW)
ms = d[:markersize]
ms = if typeof(ms) <: AVec
warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
mean(ms) * Gadfly.px
else
ms * Gadfly.px
@@ -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)]
@@ -558,7 +558,7 @@ function createGadflyAnnotationObject(x, y, txt::PlotText)
))
end
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
@@ -614,7 +614,7 @@ function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
@@ -677,7 +677,7 @@ setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# -------------------------------------------------------------------------
function doshow{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P})
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
@@ -692,7 +692,7 @@ getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.show{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P})
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
func = getGadflyWriteFunc($mime())
doshow(io, func, plt)
end
+1 -1
View File
@@ -2,7 +2,7 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes
immutable ShapeGeometry <: Gadfly.GeometryElement
struct ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol
+2 -2
View File
@@ -61,7 +61,7 @@ end
# ----------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
@@ -76,7 +76,7 @@ function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
+6 -6
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
@@ -150,7 +150,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
end
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
elseif !(ticks in (nothing, :none, :auto))
warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
end
# change the scale
@@ -161,7 +161,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
scaletype in supported_scales() || @warn("Unsupported scale type: ", scaletype)
end
end
@@ -218,7 +218,7 @@ function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
marker[:attach](plt.o.widget)
end
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createQwtAnnotation(plt, ann...)
end
@@ -233,7 +233,7 @@ function getxy(plt::Plot{QwtBackend}, i::Int)
series.x, series.y
end
function setxy!{X,Y}(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.o.lines[i]
series.x, series.y = xy
plt
+2 -2
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
@@ -217,7 +217,7 @@ function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::Abs
Winston.text(x, y, val)
end
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createWinstonAnnotationObject(plt, ann...)
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
+26 -26
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
@@ -34,9 +34,9 @@ getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme{T<:Real}(s::Symbol, vals::AVec{T}; kw...) = ColorGradient(s, vals; kw...)
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme{T<:Colorant}(cs::AVec{T}; kw...) = ColorGradient(cs; kw...)
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
@@ -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)
@@ -98,7 +98,7 @@ const _gradients = KW(
:lighttest => map(c -> lighten(c, 0.3), _testColors),
)
function register_gradient_colors{C<:Colorant}(name::Symbol, colors::AVec{C})
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
_gradients[name] = colors
end
@@ -109,24 +109,24 @@ default_gradient() = ColorGradient(:inferno)
# --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
immutable ColorGradient <: ColorScheme
struct ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient{S<:Real}(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
function ColorGradient(cs::AVec, vals::AVec{S} = 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
# # otherwise interpolate evenly between the minval and maxval
# minval, maxval = minimum(vals), maximum(vals)
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
# vs = Float64[interpolate(minval, maxval, w) for w in range(0, stop = 1, length = length(cs))]
# 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
@@ -138,16 +138,16 @@ Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
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
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
# ColorGradient(map(convertColor, cs), vals; kw...)
# end
@@ -208,7 +208,7 @@ end
# --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant"
immutable ColorFunction <: ColorScheme
struct ColorFunction <: ColorScheme
f::Function
end
@@ -217,7 +217,7 @@ getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant"
immutable ColorZFunction <: ColorScheme
struct ColorZFunction <: ColorScheme
f::Function
end
@@ -226,7 +226,7 @@ getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
immutable ColorVector <: ColorScheme
struct ColorVector <: ColorScheme
v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end
@@ -238,7 +238,7 @@ getColorVector(scheme::ColorVector) = scheme.v
# --------------------------------------------------------------
"Wraps a single color"
immutable ColorWrapper <: ColorScheme
struct ColorWrapper <: ColorScheme
c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
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
@@ -347,8 +347,8 @@ function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numco
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette{C<:Colorant}(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
function get_color_palette(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
palette
end
+12 -12
View File
@@ -5,21 +5,21 @@
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
const FuncOrFuncs = @compat(Union{Function, AVec{Function}})
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::@compat(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
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
@@ -39,7 +39,7 @@ convertToAnyVector(s::Surface, d::KW) = Any[s], 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)
@@ -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!")
# --------------------------------------------------------------------
+179 -69
View File
@@ -1,7 +1,7 @@
"""
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
"""
type PlotExample
mutable struct PlotExample
header::AbstractString
desc::AbstractString
exprs::Vector{Expr}
@@ -18,11 +18,18 @@ PlotExample("Lines",
),
PlotExample("Functions, adding data, and animations",
"Plot multiple functions. You can also put the function first, or use the form `plot(f, xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data: `x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with `push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the animation.",
"""
Plot multiple functions. You can also put the function first, or use the form `plot(f,
xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data:
`x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with
`push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available
to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the
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
@@ -37,23 +44,35 @@ PlotExample("Parametric plots",
),
PlotExample("Colors",
"Access predefined palettes (or build your own with the `colorscheme` method). Line/marker colors are auto-generated from the plot's palette, unless overridden. Set the `z` argument to turn on series gradients.",
"""
Access predefined palettes (or build your own with the `colorscheme` method).
Line/marker colors are auto-generated from the plot's palette, unless overridden. Set
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, lab="grad")
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.-0.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y.-0.5).+4,
lab="grad")
end)]
),
PlotExample("Global",
"Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow you to pass a tuple or value which will be mapped to the relevant args automatically. The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`, `yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`",
"""
Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow
you to pass a tuple or value which will be mapped to the relevant args automatically.
The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during
the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`,
`yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`
""",
[:(begin
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]))
vline!([5,10])
title!("TITLE")
yaxis!("YLABEL", :log10)
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, dims = 1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
vline!([5,10])
title!("TITLE")
yaxis!("YLABEL", :log10)
end)]
),
@@ -66,14 +85,21 @@ PlotExample("Global",
PlotExample("Images",
"Plot an image. y-axis is set to flipped",
[:(begin
import Images
img = Images.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
import FileIO
img = FileIO.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
plot(img)
end)]
),
PlotExample("Arguments",
"Plot multiple series with different numbers of points. Mix arguments that apply to all series (marker/markersize) with arguments unique to each series (colors). Special arguments `line`, `marker`, and `fill` will automatically figure out what arguments to set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with `line`.) Note that we pass a matrix of colors, and this applies the colors to each series.",
"""
Plot multiple series with different numbers of points. Mix arguments that apply to all
series (marker/markersize) with arguments unique to each series (colors). Special
arguments `line`, `marker`, and `fill` will automatically figure out what arguments to
set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with
`line`.) Note that we pass a matrix of colors, and this applies the colors to each
series.
""",
[:(begin
ys = Vector[rand(10), rand(20)]
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,stroke(3,:gray)))
@@ -115,12 +141,13 @@ PlotExample("Line types",
PlotExample("Line styles",
"",
[:(begin
styles = filter(s -> s in Plots.supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20,n),1)
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
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), dims = 1)
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
),
PlotExample("Marker types",
@@ -129,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)]
),
@@ -145,79 +172,105 @@ PlotExample("Bar",
PlotExample("Histogram",
"",
[:(begin
histogram(randn(1000), nbins=20)
histogram(randn(1000), bins = :scott, weights = repeat(1:5, outer = 200))
end)]
),
PlotExample("Subplots",
"""
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate arbitrarily complex subplot layouts.
""",
"""
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate
arbitrarily complex subplot layouts.
""",
[:(begin
l = @layout([a{0.1h}; b [c;d e]])
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=false)
l = @layout([a{0.1h}; b [c;d e]])
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false,
ticks=nothing, border=:none)
end)]
),
PlotExample("Adding to subplots",
"Note here the automatic grid layout, as well as the order in which new series are added to the plots.",
"""
Note here the automatic grid layout, as well as the order in which new series are added
to the plots.
""",
[:(begin
plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black])
plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbow],
bg_inside=[:orange :pink :darkblue :black])
end)]
),
PlotExample("",
"",
[:(begin
srand(111)
Random.srand(111)
plot!(Plots.fakedata(100,10))
end)]
),
PlotExample("Open/High/Low/Close",
"Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y` argument. This uses recipes to first convert the tuples to OHLC objects, and subsequently create a :path series with the appropriate line segments.",
"""
Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y`
argument. This uses recipes to first convert the tuples to OHLC objects, and
subsequently create a :path series with the appropriate line segments.
""",
[:(begin
n=20
hgt=rand(n)+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
y = OHLC[(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i], closepct[i]*hgt[i]+bot[i]) for i in 1:n]
ohlc(y)
n=20
hgt=rand(n).+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
y = OHLC[(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i],
closepct[i]*hgt[i]+bot[i]) for i in 1:n]
ohlc(y)
end)]
),
PlotExample("Annotations",
"The `annotations` keyword is used for text annotations in data-coordinates. Pass in a tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(; annotation=ann)`. Series annotations are used for annotating individual data points. They require only the annotation... x/y values are computed. A `PlotText` object can be build with the method `text(string, attr...)`, which wraps font and color attributes.",
"""
The `annotations` keyword is used for text annotations in data-coordinates. Pass in a
tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(;
annotation=ann)`. Series annotations are used for annotating individual data points.
They require only the annotation... x/y values are computed. A `PlotText` object can be
build with the method `text(string, attr...)`, which wraps font and color attributes.
""",
[:(begin
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), series_annotations = ["series","annotations","map","to","series",text("data",:green)])
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!(range(2, stop=8, length=6), rand(6), marker=(50,0.2,:orange),
series_annotations = ["series","annotations","map","to","series",
text("data",:green)])
end)]
),
PlotExample("Custom Markers",
"A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and the size is expected to be rougly the area of the unit circle.",
"""A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported
backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and
the size is expected to be rougly the area of the unit circle.
""",
[:(begin
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
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)
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
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)]
),
PlotExample("Contours",
"Any value for fill works here. We first build a filled contour from a function, then an unfilled contour from a matrix.",
"""
Any value for fill works here. We first build a filled contour from a function, then an
unfilled contour from a matrix.
""",
[:(begin
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)
@@ -238,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
@@ -252,7 +305,7 @@ PlotExample("DataFrames",
[:(begin
import RDatasets
iris = RDatasets.dataset("datasets", "iris")
scatter(iris, :SepalLength, :SepalWidth, group=:Species,
@df iris scatter(:SepalLength, :SepalWidth, group=:Species,
title = "My awesome plot", xlabel = "Length", ylabel = "Width",
marker = (0.5, [:cross :hex :star7], 12), bg=RGB(.2,.2,.2))
end)]
@@ -262,14 +315,15 @@ PlotExample("Groups and Subplots",
"",
[:(begin
group = rand(map(i->"group $i",1:4),100)
plot(rand(100), layout=@layout([a b;c]), group=group, linetype=[:bar :scatter :steppre])
plot(rand(100), layout=@layout([a b;c]), group=group,
linetype=[:bar :scatter :steppre], linecolor = :match)
end)]
),
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)]
@@ -288,9 +342,10 @@ PlotExample("Heatmap, categorical axes, and aspect_ratio",
PlotExample("Layouts, margins, label rotation, title location",
"",
[:(begin
using Plots.PlotMeasures # for Measures, e.g. mm and px
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
title_location=:left, left_margin=[20mm 0mm],
bottom_margin=50px, xrotation=60)
bottom_margin=10px, xrotation=60)
end)]
),
@@ -299,8 +354,8 @@ PlotExample("Boxplot and Violin series recipes",
[:(begin
import RDatasets
singers = RDatasets.dataset("lattice", "singer")
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue))
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
@df singers violin(:VoicePart, :Height, line = 0, fill = (0.2, :blue))
@df singers boxplot!(:VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
end)]
),
@@ -313,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
@@ -321,11 +376,59 @@ 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 `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`",
"""
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
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
plot(spy(a, markershape = :dtriangle), spy(b), markersize = 3, title = ["Unique nonzeros" "Different nonzeros"])
plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"])
end)]
),
PlotExample("Magic grid argument",
"""
The grid lines can be modified individually for each axis with the magic `grid` argument.
""",
[:(begin
x = rand(10)
p1 = plot(x, title = "Default looks")
p2 = plot(x, grid = (:y, :olivedrab, :dot, 1, 0.9), title = "Modified y grid")
p3 = plot(deepcopy(p2), title = "Add x grid")
xgrid!(p3, :on, :cadetblue, 2, :dashdot, 0.4)
plot(p1, p2, p3, layout = (1, 3), label = "", fillrange = 0, fillalpha = 0.3)
end)]
),
PlotExample("Framestyle",
"""
The style of the frame/axes of a (sub)plot can be changed with the `framestyle`
attribute. The default framestyle is `:axes`.
""",
[:(begin
scatter(fill(randn(10), 6), fill(randn(10), 6),
framestyle = [:box :semi :origin :zerolines :grid :none],
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
color = RowVector(1:6), layout = 6, label = "", markerstrokewidth = 0,
ticks = -2:2)
end)]
),
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.
""",
[:(begin
t = range(0, stop=1, length=100)
θ = 6π .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z=t, linewidth=3, legend=false)
p2 = scatter(x, y, marker_z=t, color=:bluesreds, legend=false)
plot(p1, p2)
end)]
),
@@ -336,7 +439,7 @@ PlotExample("Spy",
# 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)
@@ -348,6 +451,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
end
# generate all plots and create a dict mapping idx --> plt
"""
test_examples(pkgname[, idx]; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing
Run the `idx` test example for a given backend, or all examples if `idx`
is not specified.
"""
function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing)
Plots._debugMode.on = debug
+70
View File
@@ -0,0 +1,70 @@
function __init__()
include(joinpath(@__DIR__, "backends", "plotly.jl"))
include(joinpath(@__DIR__, "backends", "gr.jl"))
include(joinpath(@__DIR__, "backends", "web.jl"))
@require GLVisualize = "4086de5b-f4b6-55f3-abb0-b8c73827585f" include(joinpath(@__DIR__, "backends", "gr.jl"))
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" include(joinpath(@__DIR__, "backends", "plotlyjs.jl"))
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl"))
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl"))
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
if IJulia.inited
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_extra_mime_info!(plt::Plot, out::Dict) = out
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
out
end
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function IJulia.display_dict(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)
end
out = Dict()
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
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
_extra_mime_info!(plt, out)
out
end
ENV["MPLBACKEND"] = "Agg"
end
end
end
+28 -20
View File
@@ -1,23 +1,19 @@
# NOTE: (0,0) is the top-left !!!
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm
Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
#Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
#Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
Base.zero(::Type{typeof(mm)}) = 0mm
Base.one(::Type{typeof(mm)}) = 1mm
Base.typemin(::typeof(mm)) = -Inf*mm
Base.typemax(::typeof(mm)) = Inf*mm
Base.convert{F<:AbstractFloat}(::Type{F}, l::AbsoluteLength) = convert(F, l.value)
Base.convert(::Type{F}, l::AbsoluteLength) where {F<:AbstractFloat} = convert(F, l.value)
# TODO: these are unintuitive and may cause tricky bugs
# Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
@@ -99,7 +95,7 @@ end
# -----------------------------------------------------------
# points combined by x/y, pct, and length
type MixedMeasures
mutable struct MixedMeasures
xy::Float64
pct::Float64
len::AbsoluteLength
@@ -133,7 +129,12 @@ make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h
make_measure_vert(m::Measure) = m
"""
bbox(x, y, w, h [,originargs...])
bbox(layout)
Create a bounding box for plotting
"""
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
oargs = vcat(oarg1, originargs...)
orighor = :left
@@ -146,7 +147,7 @@ function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
elseif oarg in (:top, :bottom, :vcenter)
origver = oarg
else
warn("Unused origin arg in bbox construction: $oarg")
@warn("Unused origin arg in bbox construction: $oarg")
end
end
bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver)
@@ -215,7 +216,7 @@ bottompad(layout::AbstractLayout) = 0mm
# RootLayout
# this is the parent of the top-level layout
immutable RootLayout <: AbstractLayout end
struct RootLayout <: AbstractLayout end
Base.parent(::RootLayout) = nothing
parent_bbox(::RootLayout) = defaultbox
@@ -225,7 +226,7 @@ bbox(::RootLayout) = defaultbox
# EmptyLayout
# contains blank space
type EmptyLayout <: AbstractLayout
mutable struct EmptyLayout <: AbstractLayout
parent::AbstractLayout
bbox::BoundingBox
attr::KW # store label, width, and height for initialization
@@ -243,7 +244,7 @@ _update_min_padding!(layout::EmptyLayout) = nothing
# GridLayout
# nested, gridded layout with optional size percentages
type GridLayout <: AbstractLayout
mutable struct GridLayout <: AbstractLayout
parent::AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox
@@ -253,6 +254,13 @@ type GridLayout <: AbstractLayout
attr::KW
end
"""
grid(args...; kw...)
Create a grid layout for subplots. `args` specify the dimensions, e.g.
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two
columns of different width.
"""
grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout(dims...;
@@ -260,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),
@@ -349,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])
@@ -473,12 +481,12 @@ function layout_args(n::Integer)
GridLayout(nr, nc), n
end
function layout_args{I<:Integer}(sztup::NTuple{2,I})
function layout_args(sztup::NTuple{2,I}) where I<:Integer
nr, nc = sztup
GridLayout(nr, nc), nr*nc
end
function layout_args{I<:Integer}(sztup::NTuple{3,I})
function layout_args(sztup::NTuple{3,I}) where I<:Integer
n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n
@@ -558,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)
+57 -102
View File
@@ -39,7 +39,7 @@ ps(fn::AbstractString) = ps(current(), fn)
function eps(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "eps")
io = open(fn, "w")
writemime(io, MIME("image/eps"), plt)
show(io, MIME("image/eps"), plt)
close(io)
end
eps(fn::AbstractString) = eps(current(), fn)
@@ -97,6 +97,13 @@ function addExtension(fn::AbstractString, ext::AbstractString)
end
end
"""
savefig([plot,] filename)
Save a Plot (the current plot if `plot` is not passed) to file. The file
type is inferred from the file extension. All backends support png and pdf
file types, some also support svg, ps, eps, html and tex.
"""
function savefig(plt::Plot, fn::AbstractString)
# get the extension
@@ -119,7 +126,11 @@ savefig(fn::AbstractString) = savefig(current(), fn)
# ---------------------------------------------------------
"""
gui([plot])
Display a plot using the backends' gui window
"""
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
# IJulia only... inline display
@@ -135,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)
@@ -146,67 +158,70 @@ 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,
:glvisualize => :png
:glvisualize => :png,
:plotlyjs => :html,
:plotly => :html
)
# 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)
end
if output_type == :png
# info("writing png to html output")
# @info("writing png to html output")
print(io, "<img src=\"data:image/png;base64,", base64encode(show, MIME("image/png"), plt), "\" />")
elseif output_type == :svg
# info("writing svg to html output")
# @info("writing svg to html output")
show(io, MIME("image/svg+xml"), plt)
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{B}(io::IO, m, plt::Plot{B})
# Base.show_backtrace(STDOUT, backtrace())
warn("_show is not defined for this backend. m=", string(m))
# delegate showable to _show instead
function Base.showable(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{B}(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B})
prepare_output(plt)
_show(io, m, plt)
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)
if haskey(io, :juno_plotsize)
showjuno(io, m, plt)
else
prepare_output(plt)
_show(io, m, plt)
end
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())
# ---------------------------------------------------------
# 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
@@ -220,14 +235,10 @@ if is_installed("FileIO")
FileIO.save(pngfn, s)
# now write from the file
write(io, readall(open(pngfn)))
write(io, read(open(pngfn), String))
end
end
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
@@ -244,82 +255,26 @@ end
#
# html_output_format("svg")
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
const _ijulia_output = String["text/html"]
function setup_ijulia()
# override IJulia inline display
if isijulia()
@eval begin
import IJulia
export set_ijulia_output
function set_ijulia_output(mimestr::AbstractString)
# info("Setting IJulia output format to $mimestr")
global _ijulia_output
_ijulia_output[1] = mimestr
end
function IJulia.display_dict(plt::Plot)
global _ijulia_output
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
end
# 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
end
@eval set_ijulia_output("text/html")
end
end
# ---------------------------------------------------------
# Atom PlotPane
# ---------------------------------------------------------
function showjuno(io::IO, m, plt)
sz = plt[:size]
dpi = plt[:dpi]
thickness_scaling = plt[:thickness_scaling]
function setup_atom()
if isatom()
@eval import Atom, Media
Media.media(Plot, Media.Plot)
jsize = get(io, :juno_plotsize, [400, 500])
# default text/plain so it doesn't complain
function Base.show{B}(io::IO, ::MIME"text/plain", plt::Plot{B})
print(io, "Plot{$B}()")
end
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
function Media.render(e::Atom.Editor, plt::Plot)
Media.render(e, nothing)
end
prepare_output(plt)
_show(io, m, plt)
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
# this is like "display"... sends an html div with the plot to the PlotPane
function Media.render(pane::Atom.PlotPane, plt::Plot)
# temporarily overwrite size to be Atom.plotsize
sz = plt[:size]
plt[:size] = Juno.plotsize()
Media.render(pane, Atom.div(".fill", Atom.HTML(stringmime(MIME("text/html"), plt))))
plt[:size] = sz
end
# special handling for PlotlyJS
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyJSBackend})
display(Plots.PlotsDisplay(), plt)
end
else
#
function Media.render(pane::Atom.PlotPane, plt::Plot)
display(Plots.PlotsDisplay(), plt)
s = "PlotPane turned off. Unset ENV[\"PLOTS_USE_ATOM_PLOTPANE\"] and restart Julia to enable it."
Media.render(pane, Atom.div(Atom.HTML(s)))
end
end
# special handling for plotly... use PlotsDisplay
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
display(Plots.PlotsDisplay(), plt)
s = "PlotPane turned off. The plotly backend cannot render in the PlotPane due to javascript issues. Plotlyjs is similar to plotly and is compatible with the plot pane."
Media.render(pane, Atom.div(Atom.HTML(s)))
end
end
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end
+37 -33
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
@@ -60,29 +62,26 @@ function _process_userrecipes(plt::Plot, d::KW, args)
args = _preprocess_args(d, args, still_to_process)
# for plotting recipes, swap out the args and update the parameter dictionary
# we are keeping a queue of series that still need to be processed.
# we are keeping a stack of series that still need to be processed.
# each pass through the loop, we pop one off and apply the recipe.
# the recipe will return a list a Series objects... the ones that are
# finished (no more args) get added to the kw_list, and the rest go into the queue
# for processing.
# finished (no more args) get added to the kw_list, the ones that are not
# are placed on top of the stack and are then processed further.
kw_list = KW[]
while !isempty(still_to_process)
# grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes)
next_series = shift!(still_to_process)
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
for recipedata in rd_list
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(recipedata) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
end
if isempty(recipedata.args)
_process_userrecipe(plt, kw_list, recipedata)
else
# args are non-empty, so there's still processing to do... add it back to the queue
push!(still_to_process, recipedata)
end
# 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 = 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")
end
if isempty(next_series.args)
_process_userrecipe(plt, kw_list, next_series)
else
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
prepend!(still_to_process,rd_list)
end
end
@@ -154,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,
@@ -213,7 +212,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# TODO: init subplots here
_update_plot_args(plt, d)
if !plt.init
plt.o = _create_backend_figure(plt)
plt.o = Base.invokelatest(_create_backend_figure, plt)
# create the layout and subplots from the inputs
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
@@ -267,7 +266,7 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# extract subplot/axis attributes from kw and add to sp_attr
attr = KW()
for (k,v) in kw
for (k,v) in collect(kw)
if haskey(_subplot_defaults, k) || haskey(_axis_defaults_byletter, k)
attr[k] = pop!(kw, k)
end
@@ -304,7 +303,7 @@ end
# getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes
function _prepare_subplot{T}(plt::Plot{T}, d::KW)
function _prepare_subplot(plt::Plot{T}, d::KW) where T
st::Symbol = d[:seriestype]
sp::Subplot{T} = d[:subplot]
sp_idx = get_subplot_index(plt, sp)
@@ -330,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
@@ -360,13 +359,17 @@ end
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
# adjust extrema and discrete info
if st == :image
w, h = size(d[:z])
expand_extrema!(sp[:xaxis], (0,w))
expand_extrema!(sp[:yaxis], (0,h))
sp[:yaxis].d[:flip] = true
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
expand_extrema!(sp[:xaxis], (xmin, xmax))
expand_extrema!(sp[:yaxis], (ymin, ymax))
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
expand_extrema!(sp, d)
end
# expand for zerolines (axes through origin)
if sp[:framestyle] in (:origin, :zerolines)
expand_extrema!(sp[:xaxis], 0.0)
expand_extrema!(sp[:yaxis], 0.0)
end
end
function _add_the_series(plt, sp, d)
@@ -397,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
@@ -412,7 +416,7 @@ function _process_seriesrecipe(plt::Plot, d::KW)
end
_process_seriesrecipe(plt, data.d)
else
warn("Unhandled recipe: $(data)")
@warn("Unhandled recipe: $(data)")
break
end
end
+30 -23
View File
@@ -1,18 +1,22 @@
type CurrentPlot
nullableplot::Nullable{AbstractPlot}
mutable struct CurrentPlot
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()
Returns the Plot object for the current plot
"""
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)
# ---------------------------------------------------------
@@ -29,7 +33,7 @@ convertSeriesIndex(plt::Plot, n::Int) = n
"""
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
```
plot(args...; kw...) # creates a new plot window, and sets it to be the current
@@ -38,11 +42,12 @@ The main plot command. Use `plot` to create a new plot object, and `plot!` to a
```
There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected.
When you pass in matrices, it splits by columns. See the documentation for more info.
When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr([attr])`
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)
@@ -60,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
@@ -80,7 +85,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
# TODO: replace this with proper processing from a merged user_attr KW
# update plot args, first with existing plots, then override with d
for p in plts
_update_plot_args(plt, p.attr)
_update_plot_args(plt, copy(p.attr))
plt.n += p.n
end
_update_plot_args(plt, d)
@@ -96,8 +101,13 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
end
end
# create the layout and initialize the subplots
# create the layout
plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts))
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# initialize the subplots
cmdidx = 1
for (idx, sp) in enumerate(plt.subplots)
_initialize_subplot(plt, sp)
@@ -121,9 +131,6 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
_update_subplot_args(plt, sp, d, idx, false)
end
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# finish up
current(plt)
_do_plot_show(plt, get(d, :show, default(:show)))
@@ -161,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
# --------------------------------
@@ -170,7 +177,7 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
kw_list = _process_userrecipes(plt, d, args)
# info(1)
# @info(1)
# map(DD, kw_list)
@@ -185,11 +192,11 @@ 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
# info(2)
# @info(2)
# map(DD, kw_list)
# --------------------------------
@@ -205,7 +212,7 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
# "SERIES RECIPES"
# --------------------------------
# info(3)
# @info(3)
# map(DD, kw_list)
for kw in kw_list
@@ -276,11 +283,11 @@ end
function plot(sp::Subplot, args...; kw...)
plt = sp.plt
plot(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
plot(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end
function plot!(sp::Subplot, args...; kw...)
plt = sp.plt
plot!(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end
# --------------------------------------------------------------------
+7 -1
View File
@@ -14,6 +14,12 @@ function lookup_aliases(attrtype, attribute)
error("There is no attribute named $attribute in $attrtype")
end
"""
plotattr([attr])
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
The information is the same as that given on https://juliaplots.github.io/attributes/.
"""
function plotattr()
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
end
@@ -40,7 +46,7 @@ function plotattr(attrtype::Symbol, attribute::AbstractString)
attribute = Symbol(lookup_aliases(attrtype, attribute))
desc = get(_arg_desc, attribute, "")
first_period_idx = findfirst(desc, '.')
first_period_idx = findfirst(isequal('.'), desc)
typedesc = desc[1:first_period_idx-1]
desc = strip(desc[first_period_idx+1:end])
als = keys(filter((_,v)->v==attribute, _keyAliases)) |> collect |> sort
+217 -121
View File
@@ -47,7 +47,7 @@ end
num_series(x::AMat) = size(x,2)
num_series(x) = 1
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::AbstractPlot) = throw(MethodError("Unmatched plot recipe: $T"))
RecipesBase.apply_recipe(d::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
@@ -79,55 +79,101 @@ function hvline_limits(axis::Axis)
end
@recipe function f(::Type{Val{:hline}}, x, y, z)
xmin, xmax = hvline_limits(d[:subplot][:xaxis])
n = length(y)
newx = repmat(Float64[xmin, xmax, NaN], n)
newx = repeat(Float64[-1, 1, NaN], n)
newy = vec(Float64[yi for i=1:3,yi=y])
x := newx
y := newy
seriestype := :path
seriestype := :straightline
()
end
@deps hline path
@deps hline straightline
@recipe function f(::Type{Val{:vline}}, x, y, z)
ymin, ymax = hvline_limits(d[:subplot][:yaxis])
n = length(y)
newx = vec(Float64[yi for i=1:3,yi=y])
newy = repmat(Float64[ymin, ymax, NaN], n)
newy = repeat(Float64[-1, 1, NaN], n)
x := newx
y := newy
seriestype := :path
seriestype := :straightline
()
end
@deps vline path
@deps vline straightline
@recipe function f(::Type{Val{:hspan}}, x, y, z)
n = div(length(y), 2)
newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
newy = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...)
linewidth --> 0
x := newx
y := newy
seriestype := :shape
()
end
@deps hspan shape
@recipe function f(::Type{Val{:vspan}}, x, y, z)
n = div(length(y), 2)
newx = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...)
newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
linewidth --> 0
x := newx
y := newy
seriestype := :shape
()
end
@deps vspan shape
# ---------------------------------------------------------------------------
# path and scatter
# create a path from steps
@recipe function f(::Type{Val{:scatterpath}}, x, y, z)
x := x
y := y
seriestype := :scatter
@series begin
seriestype := :path
label := ""
primary := false
()
end
()
end
@deps scatterpath path scatter
# ---------------------------------------------------------------------------
# steps
function make_steps(x, y, st)
make_steps(x, st) = x
function make_steps(x::AbstractArray, st)
n = length(x)
n == 0 && return zeros(0),zeros(0)
newx, newy = zeros(2n-1), zeros(2n-1)
for i=1:n
idx = 2i-1
n == 0 && return zeros(0)
newx = zeros(2n - 1)
for i in 1:n
idx = 2i - 1
newx[idx] = x[i]
newy[idx] = y[i]
if i > 1
newx[idx-1] = x[st == :steppre ? i-1 : i]
newy[idx-1] = y[st == :steppre ? i : i-1]
newx[idx - 1] = x[st == :pre ? i : i - 1]
end
end
newx, newy
return newx
end
make_steps(t::Tuple, st) = Tuple(make_steps(ti, st) for ti in t)
# create a path from steps
@recipe function f(::Type{Val{:steppre}}, x, y, z)
d[:x], d[:y] = make_steps(x, y, :steppre)
plotattributes[:x] = make_steps(x, :post)
plotattributes[:y] = make_steps(y, :pre)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre)
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
@@ -144,11 +190,15 @@ end
# create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z)
d[:x], d[:y] = make_steps(x, y, :steppost)
plotattributes[:x] = make_steps(x, :pre)
plotattributes[:y] = make_steps(y, :post)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post)
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
@@ -170,9 +220,9 @@ end
# create vertical line segments from fill
@recipe function f(::Type{Val{:sticks}}, x, y, z)
n = length(x)
fr = d[:fillrange]
fr = plotattributes[:fillrange]
if fr == nothing
yaxis = d[:subplot][:yaxis]
yaxis = plotattributes[:subplot][:yaxis]
fr = if yaxis[:scale] == :identity
0.0
else
@@ -191,7 +241,7 @@ end
seriestype := :path
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
@@ -224,7 +274,7 @@ end
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30)
args = z != nothing ? (x,y,z) : (x,y)
newx, newy = zeros(0), zeros(0)
fr = d[:fillrange]
fr = plotattributes[:fillrange]
newfr = fr != nothing ? zeros(0) : nothing
newz = z != nothing ? zeros(0) : nothing
# lz = d[:line_z]
@@ -234,7 +284,7 @@ end
# where the points are the control points of the curve
for rng in iter_segments(args...)
length(rng) < 2 && continue
ts = linspace(0, 1, npoints)
ts = range(0, stop = 1, length = npoints)
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts))
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts))
if z != nothing
@@ -274,9 +324,9 @@ end
# create a bar plot as a filled step function
@recipe function f(::Type{Val{:bar}}, x, y, z)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(d, x, y)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y)
nx, ny = length(procx), length(procy)
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi=procx]
procx = if nx == ny
cv
@@ -287,15 +337,19 @@ end
end
# compute half-width of bars
bw = d[:bar_width]
bw = plotattributes[:bar_width]
hw = if bw == nothing
0.5ignorenan_mean(diff(procx))
if nx > 1
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx)))
else
0.5 * _bar_width
end
else
Float64[0.5_cycle(bw,i) for i=1:length(procx)]
end
# make fillto a vector... default fills to 0
fillto = d[:fillrange]
fillto = plotattributes[:fillrange]
if fillto == nothing
fillto = 0
end
@@ -320,7 +374,7 @@ end
expand_extrema!(axis, widen(ignorenan_extrema(xseg.pts)...))
# switch back
if !isvertical(d)
if !isvertical(plotattributes)
xseg, yseg = yseg, xseg
end
@@ -335,6 +389,34 @@ end
end
@deps bar shape
# ---------------------------------------------------------------------------
# Plots Heatmap
@recipe function f(::Type{Val{:plots_heatmap}}, x, y, z)
xe, ye = heatmap_edges(x), heatmap_edges(y)
m, n = size(z.surf)
x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n)
fz = zeros(m * n)
for i in 1:m # y
for j in 1:n # x
k = (j - 1) * m + i
inds = (6 * (k - 1) + 1):(6 * k - 1)
x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]]
y_pts[inds] .= [ye[i], ye[i], ye[i + 1], ye[i + 1], ye[i]]
fz[k] = z.surf[i, j]
end
end
ensure_gradient!(plotattributes, :fillcolor, :fillalpha)
fill_z := fz
line_z := fz
x := x_pts
y := y_pts
z := nothing
seriestype := :shape
label := ""
widen --> false
()
end
@deps plots_heatmap shape
# ---------------------------------------------------------------------------
# Histograms
@@ -343,9 +425,9 @@ _bin_centers(v::AVec) = (v[1:end-1] + v[2:end]) / 2
_is_positive(x) = (x > 0) && !(x 0)
_positive_else_nan{T}(::Type{T}, x::Real) = _is_positive(x) ? T(x) : T(NaN)
_positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN)
function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector, scale::Symbol)
function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) where T<:AbstractFloat
if scale in _logScales
[_positive_else_nan(T, x) for x in V]
else
@@ -354,7 +436,7 @@ function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector,
end
function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real
if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
else
@@ -363,7 +445,7 @@ function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
end
function _preprocess_binbarlike_weights{T<:AbstractFloat}(::Type{T}, w, wscale::Symbol)
function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:AbstractFloat
w_adj = _scale_adjusted_values(T, w, wscale)
w_min = ignorenan_minimum(w_adj)
w_max = ignorenan_maximum(w_adj)
@@ -389,8 +471,8 @@ end
@recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
if (d[:bar_width] == nothing)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
if (plotattributes[:bar_width] == nothing)
bar_width := diff(edge)
end
x := _bin_centers(edge)
@@ -402,7 +484,7 @@ end
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
xerror := diff(edge)/2
x := _bin_centers(edge)
y := weights
@@ -416,21 +498,25 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
log_scale_x = xscale in _logScales
log_scale_y = yscale in _logScales
nbins = length(linearindices(weights))
if length(linearindices(edge)) != nbins + 1
nbins = length(eachindex(weights))
if length(eachindex(edge)) != nbins + 1
error("Edge vector must be 1 longer than weight vector")
end
x = eltype(edge)[]
y = eltype(weights)[]
it_e, it_w = start(edge), start(weights)
a, it_e = next(edge, it_e)
it_tuple_e = iterate(edge)
a, it_state_e = it_tuple_e
it_tuple_e = iterate(edge, it_state_e)
it_tuple_w = iterate(weights)
last_w = eltype(weights)(NaN)
i = 1
while (!done(edge, it_e) && !done(edge, it_e))
b, it_e = next(edge, it_e)
w, it_w = next(weights, it_w)
while it_tuple_e != nothing && it_tuple_w != nothing
b, it_state_e = it_tuple_e
w, it_state_w = it_tuple_w
if (log_scale_x && a 0)
a = b/_logScaleBases[xscale]^3
@@ -454,6 +540,9 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
a = b
last_w = w
it_tuple_e = iterate(edge, it_state_e)
it_tuple_w = iterate(weights, it_state_w)
end
if (last_w != baseline)
push!(x, a)
@@ -465,17 +554,17 @@ end
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
axis = d[:subplot][Plots.isvertical(d) ? :xaxis : :yaxis]
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(d)
if !isvertical(plotattributes)
xpts, ypts = ypts, xpts
end
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := _bin_centers(edge)
@@ -497,66 +586,73 @@ end
end
Plots.@deps stepbins path
wand_edges(x...) = (@warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto)
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
_iqr(v) = quantile(v, 0.75) - quantile(v, 0.25)
_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)))
# Estimator for number of samples in one row/column of bins along each axis:
n = max(1, n_samples^(1/N))
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))
nd = N == 2 ? min(n_samples^(1/(2+N)), nd / (1-cor(first(vs), last(vs))^2)^(3//8)) : nd # the >2-dimensional case does not have a nice solution to correlations
v = vs[dim]
if mode == :auto
30
elseif mode == :sqrt # Square-root choice
_cl(sqrt(n))
mode = :fd
end
if mode == :sqrt # Square-root choice
_cl(sqrt(n_samples))
elseif mode == :sturges # Sturges' formula
_cl(log2(n)) + 1
_cl(log2(n_samples) + 1)
elseif mode == :rice # Rice Rule
_cl(2 * n^(1/3))
_cl(2 * nd)
elseif mode == :scott # Scott's normal reference rule
_cl(_span(v) / (3.5 * std(v) / n^(1/3)))
_cl(_span(v) / (3.5 * std(v) / nd))
elseif mode == :fd # FreedmanDiaconis rule
_cl(_span(v) / (2 * _iqr(v) / n^(1/3)))
_cl(_span(v) / (2 * _iqr(v) / nd))
elseif mode == :wand
wand_edges(v) # this makes this function not type stable, but the type instability does not propagate
else
error("Unknown auto-binning mode $mode")
end::Int
end
end
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) = StatsBase.histrange(vs[dim], binning, :left)
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) = binning
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} = StatsBase.histrange(vs[dim], binning, :left)
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
_hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...))
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N, Any}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
_hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) =
map(dim -> _hist_edge(vs, dim, binning), (1:N...))
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
map(dim -> _hist_edge(vs, dim, binning), (1:N...,))
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
function _make_hist{N}(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing)
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
edges = _hist_edges(vs, binning)
h = float( weights == nothing ?
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, vs, weights, edges, closed = :left)
StatsBase.fit(StatsBase.Histogram, vs, StatsBase.Weights(weights), edges, closed = :left)
)
normalize!(h, mode = _hist_norm_mode(normed))
end
@recipe function f(::Type{Val{:histogram}}, x, y, z)
seriestype := :barhist
seriestype := length(y) > 1e6 ? :stephist : :barhist
()
end
@deps histogram barhist
@recipe function f(::Type{Val{:barhist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :barbins
@@ -565,7 +661,7 @@ end
@deps barhist barbins
@recipe function f(::Type{Val{:stephist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :stepbins
@@ -574,7 +670,7 @@ end
@deps stephist stepbins
@recipe function f(::Type{Val{:scatterhist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :scatterbins
@@ -583,18 +679,18 @@ end
@deps scatterhist scatterbins
@recipe function f{T, E}(h::StatsBase.Histogram{T, 1, E})
@recipe function f(h::StatsBase.Histogram{T, 1, E}) where {T, E}
seriestype --> :barbins
st_map = Dict(
:bar => :barbins, :scatter => :scatterbins, :step => :stepbins,
:steppost => :stepbins # :step can be mapped to :steppost in pre-processing
)
seriestype := get(st_map, d[:seriestype], d[:seriestype])
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
if d[:seriestype] == :scatterbins
if plotattributes[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, h.edges[1], h.weights)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, h.edges[1], h.weights)
xerror --> diff(h.edges[1])/2
seriestype := :scatter
(Plots._bin_centers(edge), weights)
@@ -604,7 +700,7 @@ end
end
@recipe function f{H <: StatsBase.Histogram}(hv::AbstractVector{H})
@recipe function f(hv::AbstractVector{H}) where H <: StatsBase.Histogram
for h in hv
@series begin
h
@@ -641,7 +737,7 @@ Plots.@deps bins2d heatmap
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
h = _make_hist((x, y), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((x, y), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.edges[2]
z := Surface(h.weights)
@@ -651,7 +747,7 @@ end
@deps histogram2d bins2d
@recipe function f{T, E}(h::StatsBase.Histogram{T, 2, E})
@recipe function f(h::StatsBase.Histogram{T, 2, E}) where {T, E}
seriestype --> :bins2d
(h.edges[1], h.edges[2], Surface(h.weights))
end
@@ -662,7 +758,7 @@ end
@recipe function f(::Type{Val{:scatter3d}}, x, y, z)
seriestype := :path3d
if d[:markershape] == :none
if plotattributes[:markershape] == :none
markershape := :circle
end
linewidth := 0
@@ -703,7 +799,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)
@@ -725,17 +821,17 @@ end
# we will create a series of path segments, where each point represents one
# side of an errorbar
@recipe function f(::Type{Val{:yerror}}, x, y, z)
error_style!(d)
error_style!(plotattributes)
markershape := :hline
d[:x], d[:y] = error_coords(d[:x], d[:y], error_zipit(d[:yerror]))
plotattributes[:x], plotattributes[:y] = error_coords(plotattributes[:x], plotattributes[:y], error_zipit(plotattributes[:yerror]))
()
end
@deps yerror path
@recipe function f(::Type{Val{:xerror}}, x, y, z)
error_style!(d)
error_style!(plotattributes)
markershape := :vline
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
plotattributes[:y], plotattributes[:x] = error_coords(plotattributes[:y], plotattributes[:x], error_zipit(plotattributes[:xerror]))
()
end
@deps xerror path
@@ -834,9 +930,9 @@ end
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
@recipe function f(::Type{Val{:quiver}}, x, y, z)
if :arrow in supported_attrs()
quiver_using_arrows(d)
quiver_using_arrows(plotattributes)
else
quiver_using_hack(d)
quiver_using_hack(plotattributes)
end
()
end
@@ -847,7 +943,8 @@ end
# TODO: move OHLC to PlotRecipes finance.jl
type OHLC{T<:Real}
"Represent Open High Low Close data (used in finance)"
mutable struct OHLC{T<:Real}
open::T
high::T
low::T
@@ -886,10 +983,10 @@ end
# to squash ambiguity warnings...
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) = error()
@recipe f(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error()
# this must be OHLC?
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) = x, OHLC[OHLC(t...) for t in ohlc]
@recipe f(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc]
@recipe function f(x::AVec, v::AVec{OHLC})
seriestype := :path
@@ -929,6 +1026,7 @@ end
mat = g.args[1]
if length(unique(mat[mat .!= 0])) < 2
legend --> nothing
seriescolor --> cgrad([invisible(), fg_color(plotattributes)])
end
n,m = size(mat)
Plots.SliceIt, 1:m, 1:n, Surface(mat)
@@ -937,49 +1035,47 @@ end
@recipe function f(::Type{Val{:spy}}, x,y,z)
yflip := true
aspect_ratio := 1
rs, cs, zs = findnz(z.surf)
xlim := ignorenan_extrema(cs)
ylim := ignorenan_extrema(rs)
if d[:markershape] == :none
markershape := :circle
newz = fill(NaN, size(z)...)
for i in eachindex(zs)
newz[rs[i],cs[i]] = zs[i]
end
if d[:markersize] == default(:markersize)
markersize := 1
end
markerstrokewidth := 0
marker_z := zs
label := ""
x := cs
y := rs
z := nothing
seriestype := :scatter
seriestype := :heatmap
grid --> false
framestyle --> :box
x := x
y := y
z := Surface(newz)
()
end
# -------------------------------------------------
"Adds a+bx... straight line over the current plot"
function abline!(plt::Plot, a, b; kw...)
plot!(plt, [ignorenan_extrema(plt)...], x -> b + a*x; kw...)
end
"Adds a+bx... straight line over the current plot, without changing the axis limits"
abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...)
abline!(args...; kw...) = abline!(current(), args...; kw...)
# -------------------------------------------------
# Dates
# Dates & Times
dateformatter(dt) = string(convert(Date, dt))
datetimeformatter(dt) = string(convert(DateTime, dt))
dateformatter(dt) = string(Date(Dates.UTD(dt)))
datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
@recipe f(::Type{Date}, dt::Date) = (dt -> convert(Int, dt), dateformatter)
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> convert(Int, dt), datetimeformatter)
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
@recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter)
# -------------------------------------------------
# Complex Numbers
@recipe function f{T<:Number}(A::Array{Complex{T}})
@recipe function f(A::Array{Complex{T}}) where T<:Number
xguide --> "Re(x)"
yguide --> "Im(x)"
real.(A), imag.(A)
@@ -988,7 +1084,7 @@ end
# Splits a complex matrix to its real and complex parts
# Reals defaults solid, imaginary defaults dashed
# Label defaults are changed to match the real-imaginary reference / indexing
@recipe function f{T<:Real,T2}(x::AbstractArray{T},y::Array{Complex{T2}})
@recipe function f(x::AbstractArray{T},y::Array{Complex{T2}}) where {T<:Real,T2}
ylabel --> "Re(y)"
zlabel --> "Im(y)"
x,real.(y),imag.(y)
+199 -71
View File
@@ -8,19 +8,22 @@
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(d, :seriestype, :none))
# unknown
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
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector{T<:AbstractString}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
@@ -43,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)
@@ -69,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)
@@ -96,9 +99,9 @@ nobigs(v) = v
end
# not allowed
compute_xyz{F<:Function}(x::Void, y::FuncOrFuncs{F}, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz{F<:Function}(x::Void, y::Void, z::FuncOrFuncs{F}) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::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!")
# --------------------------------------------------------------------
@@ -106,7 +109,7 @@ compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# we are going to build recipes to do the processing and splitting of the args
# ensure we dispatch to the slicer
immutable SliceIt end
struct SliceIt end
# the catch-all recipes
@recipe function f(::Type{SliceIt}, x, y, z)
@@ -125,18 +128,26 @@ immutable SliceIt end
z = z.data
end
xs, _ = convertToAnyVector(x, d)
ys, _ = convertToAnyVector(y, d)
zs, _ = convertToAnyVector(z, d)
xs, _ = convertToAnyVector(x, plotattributes)
ys, _ = convertToAnyVector(y, plotattributes)
zs, _ = convertToAnyVector(z, plotattributes)
fr = pop!(d, :fillrange, nothing)
fr = pop!(plotattributes, :fillrange, nothing)
fillranges, _ = if typeof(fr) <: Number
([fr],nothing)
else
convertToAnyVector(fr, d)
convertToAnyVector(fr, plotattributes)
end
mf = length(fillranges)
rib = pop!(plotattributes, :ribbon, nothing)
ribbons, _ = if typeof(rib) <: Number
([fr],nothing)
else
convertToAnyVector(rib, plotattributes)
end
mr = length(ribbons)
# @show zs
mx = length(xs)
@@ -145,7 +156,7 @@ immutable SliceIt end
if mx > 0 && my > 0 && mz > 0
for i in 1:max(mx, my, mz)
# add a new series
di = copy(d)
di = copy(plotattributes)
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
@@ -153,6 +164,10 @@ immutable SliceIt end
fr = fillranges[mod1(i,mf)]
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
# handle ribbons
rib = ribbons[mod1(i,mr)]
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
push!(series_list, RecipeData(di, ()))
end
end
@@ -160,10 +175,10 @@ immutable SliceIt end
end
# this is the default "type recipe"... just pass the object through
@recipe f{T<:Any}(::Type{T}, v::T) = v
@recipe f(::Type{T}, v::T) where {T<:Any} = v
# this should catch unhandled "series recipes" and error with a nice message
@recipe f{V<:Val}(::Type{V}, x, y, z) = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
@recipe f(::Type{V}, x, y, z) where {V<:Val} = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
@@ -171,6 +186,7 @@ _apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
# This sort of recipe should return a pair of functions... one to convert to number,
# and one to format tick values.
function _apply_type_recipe(d, v::AbstractArray)
isempty(v) && return Float64[]
args = RecipesBase.apply_recipe(d, typeof(v[1]), v[1])[1].args
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
numfunc, formatter = args
@@ -197,16 +213,16 @@ end
# end
# don't do anything for ints or floats
_apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
_apply_type_recipe(d, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
# handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z)
did_replace = false
newx = _apply_type_recipe(d, x)
newx = _apply_type_recipe(plotattributes, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
y === newy || (did_replace = true)
newz = _apply_type_recipe(d, z)
newz = _apply_type_recipe(plotattributes, z)
z === newz || (did_replace = true)
if did_replace
newx, newy, newz
@@ -216,9 +232,9 @@ _apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
end
@recipe function f(x, y)
did_replace = false
newx = _apply_type_recipe(d, x)
newx = _apply_type_recipe(plotattributes, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
y === newy || (did_replace = true)
if did_replace
newx, newy
@@ -227,7 +243,7 @@ end
end
end
@recipe function f(y)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
if y !== newy
newy
else
@@ -240,7 +256,7 @@ end
@recipe function f(v1, v2, v3, v4, vrest...)
did_replace = false
newargs = map(v -> begin
newv = _apply_type_recipe(d, v)
newv = _apply_type_recipe(plotattributes, v)
if newv !== v
did_replace = true
end
@@ -267,13 +283,13 @@ function wrap_surfaces(d::KW)
end
end
@recipe f(n::Integer) = is3d(get(d,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
# return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f{T<:Union{Integer,AbstractFloat}}(mat::AMat{T})
if all3D(d)
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat}
if all3D(plotattributes)
n,m = size(mat)
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Surface(mat)
else
SliceIt, nothing, mat, nothing
@@ -281,11 +297,11 @@ end
end
# if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface
@recipe function f{T<:AbstractMatrix}(fmt::Formatted{T})
if all3D(d)
@recipe function f(fmt::Formatted{T}) where T<:AbstractMatrix
if all3D(plotattributes)
mat = fmt.data
n,m = size(mat)
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
else
SliceIt, nothing, fmt, nothing
@@ -293,7 +309,7 @@ end
end
# assume this is a Volume, so construct one
@recipe function f{T<:Number}(vol::AbstractArray{T,3}, args...)
@recipe function f(vol::AbstractArray{T,3}, args...) where T<:Number
seriestype := :volume
SliceIt, nothing, Volume(vol, args...), nothing
end
@@ -301,14 +317,16 @@ end
# # images - grays
@recipe function f{T<:Gray}(mat::AMat{T})
@recipe function f(mat::AMat{T}) where T<:Gray
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
n, m = size(mat)
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
end
@@ -316,16 +334,18 @@ end
# # images - colors
@recipe function f{T<:Colorant}(mat::AMat{T})
@recipe function f(mat::AMat{T}) where T<:Colorant
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
z, d[:fillcolor] = replace_image_with_heatmap(mat)
cbar --> false
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, 1:m, 1:n, Surface(z)
end
end
@@ -354,16 +374,36 @@ end
# function without range... use the current range of the x-axis
@recipe function f{F<:Function}(f::FuncOrFuncs{F})
plt = d[:plot_object]
@recipe function f(f::FuncOrFuncs{F}) where F<:Function
plt = plotattributes[:plot_object]
xmin, xmax = try
axis_limits(plt[1][:xaxis])
catch
-5, 5
xm = tryrange(f, [-5,-1,0,0.01])
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
end
f, xmin, xmax
end
# try some intervals over which the function may be defined
function tryrange(F::AbstractArray, vec)
rets = [tryrange(f, vec) for f in F] # get the preferred for each
maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all)
rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there
rets[1]
end
function tryrange(F, vec)
for v in vec
try
tmp = F(v)
return v
catch
end
end
error("$F is not a Function, or is not defined at any of the values $vec")
end
#
# # --------------------------------------------------------------------
# # 2 arguments
@@ -373,7 +413,7 @@ end
# # if functions come first, just swap the order (not to be confused with parametric functions...
# # as there would be more than one function passed in)
@recipe function f{F<:Function}(f::FuncOrFuncs{F}, x)
@recipe function f(f::FuncOrFuncs{F}, x) where F<:Function
F2 = typeof(x)
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
x, f
@@ -404,7 +444,7 @@ end
# seriestype := :path3d
# end
# end
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, x, y, z
end
@@ -414,7 +454,7 @@ end
@recipe function f(x::AVec, y::AVec, zf::Function)
# x = X <: Number ? sort(x) : x
# y = Y <: Number ? sort(y) : y
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
end
@@ -422,13 +462,45 @@ end
# # surface-like... matrix grid
@recipe function f(x::AVec, y::AVec, z::AMat)
if !like_surface(get(d, :seriestype, :none))
d[:seriestype] = :contour
if !like_surface(get(plotattributes, :seriestype, :none))
plotattributes[:seriestype] = :contour
end
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, x, y, Surface(z)
end
# # images - grays
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Gray
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, x, y, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, x, y, Surface(convert(Matrix{Float64}, mat))
end
end
# # images - colors
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Colorant
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, x, y, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, x, y, Surface(z)
end
end
#
#
# # --------------------------------------------------------------------
@@ -441,20 +513,20 @@ end
xs = adapted_grid(f, (xmin, xmax))
xs, f
end
@recipe function f{F<:Function}(fs::AbstractArray{F}, xmin::Number, xmax::Number)
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
xs, fs
end
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n)
#
# # special handling... 3D parametric function(s)
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
end
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200)
fx, fy, fz, linspace(umin, umax, numPoints)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
fx, fy, fz, range(umin, stop = umax, length = numPoints)
end
#
@@ -468,28 +540,28 @@ end
#
# # (x,y) tuples
@recipe f{R1<:Number,R2<:Number}(xy::AVec{Tuple{R1,R2}}) = unzip(xy)
@recipe f{R1<:Number,R2<:Number}(xy::Tuple{R1,R2}) = [xy[1]], [xy[2]]
@recipe f(xy::AVec{Tuple{R1,R2}}) where {R1<:Number,R2<:Number} = unzip(xy)
@recipe f(xy::Tuple{R1,R2}) where {R1<:Number,R2<:Number} = [xy[1]], [xy[2]]
#
# # (x,y,z) tuples
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::AVec{Tuple{R1,R2,R3}}) = unzip(xyz)
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]]
@recipe f(xyz::AVec{Tuple{R1,R2,R3}}) where {R1<:Number,R2<:Number,R3<:Number} = unzip(xyz)
@recipe f(xyz::Tuple{R1,R2,R3}) where {R1<:Number,R2<:Number,R3<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(d,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
@recipe f(xyuv::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f(xyuv::Tuple{R1,R2,R3,R4}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
#
# # 2D FixedSizeArrays
@recipe f{T<:Number}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = unzip(xy)
@recipe f{T<:Number}(xy::FixedSizeArrays.Vec{2,T}) = [xy[1]], [xy[2]]
@recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
@recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
#
# # 3D FixedSizeArrays
@recipe f{T<:Number}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = unzip(xyz)
@recipe f{T<:Number}(xyz::FixedSizeArrays.Vec{3,T}) = [xyz[1]], [xyz[2]], [xyz[3]]
@recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
@recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
#
# # --------------------------------------------------------------------
@@ -509,13 +581,69 @@ end
# nothing
# end
splittable_kw(key, val, lengthGroup) = false
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup)
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val)-1)...]
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
function split_kw(key, val::SeriesAnnotations, indices)
split_strs = split_kw(key, val.strs, indices)
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor)
end
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
fill!(y_mat, def_val)
for i in 1:length(groupby.groupLabels)
xi = x[groupby.groupIds[i]]
yi = y[groupby.groupIds[i]]
y_mat[getindex.(x_ind, xi), i] = yi
end
return y_mat
end
groupedvec2mat(x_ind, x, y::Tuple, groupby) = Tuple(groupedvec2mat(x_ind, x, v, groupby) for v in y)
group_as_matrix(t) = false
# split the group into 1 series per group, and set the label and idxfilter for each
@recipe function f(groupby::GroupBy, args...)
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
idxfilter --> groupby.groupIds[i]
args
lengthGroup = maximum(union(groupby.groupIds...))
if !(group_as_matrix(args[1]))
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
idxfilter --> groupby.groupIds[i]
for (key,val) in plotattributes
if splittable_kw(key, val, lengthGroup)
:($key) := split_kw(key, val, groupby.groupIds[i])
end
end
args
end
end
else
g = args[1]
if length(g.args) == 1
x = zeros(Int, lengthGroup)
for indexes in groupby.groupIds
x[indexes] = 1:length(indexes)
end
last_args = g.args
else
x = g.args[1]
last_args = g.args[2:end]
end
x_u = unique(x)
x_ind = Dict(zip(x_u, 1:length(x_u)))
for (key,val) in plotattributes
if splittable_kw(key, val, lengthGroup)
:($key) := groupedvec2mat(x_ind, x, val, groupby)
end
end
label --> reshape(groupby.groupLabels, 1, :)
typeof(g)((x_u, (groupedvec2mat(x_ind, x, arg, groupby, NaN) for arg in last_args)...))
end
end
+6 -1
View File
@@ -1,6 +1,6 @@
function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend
Subplot{T}(
parent,
Series[],
@@ -13,6 +13,11 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
)
end
"""
plotarea(subplot)
Return the bounding box of a subplot
"""
plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
+158 -32
View File
@@ -1,42 +1,168 @@
"""
theme(s::Symbol)
Specify the colour theme for plots.
"""
function theme(s::Symbol; kw...)
# reset?
if s == :none || s == :default
PlotUtils.clibrary(:Plots)
PlotUtils.default_cgrad(default = :sequential, sequential = :inferno)
default(;
bg = :white,
bglegend = :match,
bginside = :match,
bgoutside = :match,
fg = :auto,
fglegend = :match,
fggrid = :match,
fgaxis = :match,
fgtext = :match,
fgborder = :match,
fgguide = :match,
palette = :auto
)
return
end
defaults = _get_defaults(s)
_theme(s, defaults; kw...)
end
# update the default gradient and other defaults
function _get_defaults(s::Symbol)
thm = PlotThemes._themes[s]
if thm.gradient != nothing
if :defaults in fieldnames(typeof(thm))
return thm.defaults
else # old PlotTheme type
defaults = KW(
:bg => thm.bg_secondary,
:bginside => thm.bg_primary,
:fg => thm.lines,
:fgtext => thm.text,
:fgguide => thm.text,
:fglegend => thm.text,
:palette => thm.palette,
)
if thm.gradient != nothing
push!(defaults, :gradient => thm.gradient)
end
return defaults
end
end
function _theme(s::Symbol, defaults::KW; kw...)
# Reset to defaults to overwrite active theme
reset_defaults()
# Set the theme's gradient as default
if haskey(defaults, :gradient)
PlotUtils.clibrary(:misc)
PlotUtils.default_cgrad(default = :sequential, sequential = PlotThemes.gradient_name(s))
else
PlotUtils.clibrary(:Plots)
PlotUtils.default_cgrad(default = :sequential, sequential = :inferno)
end
default(;
bg = thm.bg_secondary,
bginside = thm.bg_primary,
fg = thm.lines,
fgtext = thm.text,
fgguide = thm.text,
fglegend = thm.text,
palette = thm.palette,
kw...
)
# maybe overwrite the theme's gradient
kw = KW(kw)
if haskey(kw, :gradient)
kwgrad = pop!(kw, :gradient)
for clib in clibraries()
if kwgrad in cgradients(clib)
PlotUtils.clibrary(clib)
PlotUtils.default_cgrad(default = :sequential, sequential = kwgrad)
break
end
end
end
# Set the theme's defaults
default(; defaults..., kw...)
return
end
@deprecate set_theme(s) theme(s)
@userplot ShowTheme
_color_functions = KW(
:protanopic => protanopic,
:deuteranopic => deuteranopic,
:tritanopic => tritanopic,
)
_get_showtheme_args(thm::Symbol) = thm, identity
_get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func, identity)
@recipe function showtheme(st::ShowTheme)
thm, cfunc = _get_showtheme_args(st.args...)
defaults = _get_defaults(thm)
# get the gradient
gradient_colors = get(defaults, :gradient, cgrad(:inferno).colors)
gradient = cgrad(cfunc.(RGB.(gradient_colors)))
# get the palette
palette = get(defaults, :palette, get_color_palette(:auto, plot_color(:white), 17))
palette = cfunc.(RGB.(palette))
# apply the theme
for k in keys(defaults)
k in (:gradient, :palette) && continue
def = defaults[k]
arg = get(_keyAliases, k, k)
plotattributes[arg] = if typeof(def) <: Colorant
cfunc(RGB(def))
elseif eltype(def) <: Colorant
cfunc.(RGB.(def))
elseif occursin("color", string(arg))
cfunc.(RGB.(plot_color.(def)))
else
def
end
end
srand(1)
label := ""
colorbar := false
layout := (2, 3)
for j in 1:4
@series begin
subplot := 1
palette := palette
seriestype := :path
cumsum(randn(50))
end
@series begin
subplot := 2
seriestype := :scatter
palette := palette
marker := (:circle, :diamond, :star5, :square)[j]
randn(10), randn(10)
end
end
@series begin
subplot := 3
seriestype := :histogram
palette := palette
randn(1000) .+ (0:2:4)'
end
f(r) = sin(r) / r
_norm(x, y) = norm([x, y])
x = y = range(-3π, stop = 3π, length = 30)
z = f.(_norm.(x, y'))
wi = 2:3:30
@series begin
subplot := 4
seriestype := :heatmap
seriescolor := gradient
ticks := -5:5:5
x, y, z
end
@series begin
subplot := 5
seriestype := :surface
seriescolor := gradient
x, y, z
end
n = 100
ts = range(0, stop = 10π, length = n)
x = ts .* cos.(ts)
y = (0.1ts) .* sin.(ts)
z = 1:n
@series begin
subplot := 6
seriescolor := gradient
linewidth := 3
line_z := z
x, y, z
end
end
+11 -10
View File
@@ -5,21 +5,22 @@
const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString}
immutable PlotsDisplay <: Display end
struct PlotsDisplay <: AbstractDisplay end
# -----------------------------------------------------------
immutable InputWrapper{T}
struct InputWrapper{T}
obj::T
end
wrap{T}(obj::T) = InputWrapper{T}(obj)
wrap(obj::T) where {T} = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
type Series
mutable struct Series
d::KW
end
@@ -29,7 +30,7 @@ attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
# -----------------------------------------------------------
# a single subplot
type Subplot{T<:AbstractBackend} <: AbstractLayout
mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
parent::AbstractLayout
series_list::Vector{Series} # arguments for each series
minpad::Tuple # leftpad, toppad, rightpad, bottompad
@@ -45,12 +46,12 @@ Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
# -----------------------------------------------------------
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
type Axis
mutable struct Axis
sps::Vector{Subplot}
d::KW
end
type Extrema
mutable struct Extrema
emin::Float64
emax::Float64
end
@@ -63,7 +64,7 @@ const SubplotMap = Dict{Any, Subplot}
# -----------------------------------------------------------
type Plot{T<:AbstractBackend} <: AbstractPlot{T}
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type
n::Int # number of series
attr::KW # arguments for the whole plot
@@ -87,7 +88,7 @@ end
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
Base.length(plt::Plot) = length(plt.subplots)
Base.endof(plt::Plot) = length(plt)
Base.lastindex(plt::Plot) = length(plt)
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
Base.size(plt::Plot) = size(plt.layout)
@@ -98,6 +99,6 @@ Base.ndims(plt::Plot) = 2
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
Base.endof(sp::Subplot) = length(series_list(sp))
Base.lastindex(sp::Subplot) = length(series_list(sp))
# -----------------------------------------------------------------------
+415 -74
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))
@@ -114,12 +114,12 @@ function regressionXY(x, y)
regx, regy
end
function replace_image_with_heatmap{T<:Colorant}(z::Array{T})
function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
@show T, size(z)
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
@@ -137,15 +137,15 @@ function imageHack(d::KW)
end
# ---------------------------------------------------------------
type Segments{T}
"Build line segments for plotting"
mutable struct Segments{T}
pts::Vector{T}
end
# Segments() = Segments{Float64}(zeros(0))
Segments() = Segments(Float64)
Segments{T}(::Type{T}) = Segments(T[])
Segments(::Type{T}) where {T} = Segments(T[])
Segments(p::Int) = Segments(NTuple{2,Float64}[])
@@ -157,7 +157,7 @@ to_nan(::Type{NTuple{2,Float64}}) = (NaN, NaN)
coords(segs::Segments{Float64}) = segs.pts
coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts]
function Base.push!{T}(segments::Segments{T}, vs...)
function Base.push!(segments::Segments{T}, vs...) where T
if !isempty(segments.pts)
push!(segments.pts, to_nan(T))
end
@@ -167,7 +167,7 @@ function Base.push!{T}(segments::Segments{T}, vs...)
segments
end
function Base.push!{T}(segments::Segments{T}, vs::AVec)
function Base.push!(segments::Segments{T}, vs::AVec) where T
if !isempty(segments.pts)
push!(segments.pts, to_nan(T))
end
@@ -181,30 +181,46 @@ end
# -----------------------------------------------------
# helper to manage NaN-separated segments
type SegmentsIterator
mutable struct SegmentsIterator
args::Tuple
n::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
SegmentsIterator(tup, n)
end
function iter_segments(series::Series)
x, y, z = series[:x], series[:y], series[:z]
if has_attribute_segments(series)
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{Int}[]
args = is3d(series) ? (x, y, z) : (x, y)
for seg in iter_segments(args...)
push!(segs, seg)
end
return segs
end
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)
function Base.start(itr::SegmentsIterator)
nextidx = 1
if anynan(1, itr.args)
_, nextidx = next(itr, 1)
function Base.iterate(itr::SegmentsIterator, nextidx::Int = 1)
nextidx > itr.n && return nothing
if nextidx == 1 && !any(isempty,itr.args) && anynan(1, itr.args)
nextidx = 2
end
nextidx
end
Base.done(itr::SegmentsIterator, nextidx::Int) = nextidx > itr.n
function Base.next(itr::SegmentsIterator, nextidx::Int)
i = istart = iend = nextidx
# find the next NaN, and iend is the one before
@@ -231,8 +247,8 @@ end
# Find minimal type that can contain NaN and x
# To allow use of NaN separated segments with categorical x axis
float_extended_type{T}(x::AbstractArray{T}) = Union{T,Float64}
float_extended_type{T<:Real}(x::AbstractArray{T}) = Float64
float_extended_type(x::AbstractArray{T}) where {T} = Union{T,Float64}
float_extended_type(x::AbstractArray{T}) where {T<:Real} = Float64
# ------------------------------------------------------------------------------------
@@ -240,7 +256,7 @@ float_extended_type{T<:Real}(x::AbstractArray{T}) = 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
@@ -258,27 +274,27 @@ _cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
makevec(v::AVec) = v
makevec{T}(v::T) = T[v]
makevec(v::T) where {T} = T[v]
"duplicate a single value, or pass the 2-tuple through"
maketuple(x::Real) = (x,x)
maketuple{T,S}(x::Tuple{T,S}) = x
maketuple(x::Tuple{T,S}) where {T,S} = x
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
mapFuncOrFuncs{F<:Function}(fs::AVec{F}, u::AVec) = [map(f, u) for f in fs]
mapFuncOrFuncs(fs::AVec{F}, u::AVec) where {F<:Function} = [map(f, u) for f in fs]
unzip{X,Y}(xy::AVec{Tuple{X,Y}}) = [t[1] for t in xy], [t[2] for t in xy]
unzip{X,Y,Z}(xyz::AVec{Tuple{X,Y,Z}}) = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip{X,Y,U,V}(xyuv::AVec{Tuple{X,Y,U,V}}) = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2] for t in xy]
unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip{T}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = T[t[1] for t in xy], T[t[2] for t in xy]
unzip{T}(xy::FixedSizeArrays.Vec{2,T}) = T[xy[1]], T[xy[2]]
unzip(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
unzip(xy::FixedSizeArrays.Vec{2,T}) where {T} = T[xy[1]], T[xy[2]]
unzip{T}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip{T}(xyz::FixedSizeArrays.Vec{3,T}) = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip(xyz::FixedSizeArrays.Vec{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip{T}(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip{T}(xyuv::FixedSizeArrays.Vec{4,T}) = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
unzip(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip(xyuv::FixedSizeArrays.Vec{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x)
@@ -287,7 +303,8 @@ function _expand_limits(lims, x)
lims[1] = NaNMath.min(lims[1], e1)
lims[2] = NaNMath.max(lims[2], e2)
# catch err
# warn(err)
# @warn(err)
catch
end
nothing
end
@@ -324,7 +341,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
@@ -332,13 +349,25 @@ Base.first(x::Symbol) = x
sortedkeys(d::Dict) = sort(collect(keys(d)))
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec)
const _scale_base = Dict{Symbol, Real}(
:log10 => 10,
:log2 => 2,
:ln => ,
)
function _heatmap_edges(v::AVec)
vmin, vmax = ignorenan_extrema(v)
extra = 0.5 * (vmax-vmin) / (length(v)-1)
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
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)
@@ -349,15 +378,26 @@ end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
phi, r = x, y
r = (r - rmin) / (rmax - rmin)
n = max(length(phi), length(r))
x = zeros(n)
y = zeros(n)
theta, r = filter_radial_data(x, y, r_extrema)
r = (r .- rmin) ./ (rmax .- rmin)
x = r.*cos.(theta)
y = r.*sin.(theta)
x, y
end
# Filters radial data for points within the axis limits
function filter_radial_data(theta, r, r_extrema::Tuple{Real, Real})
n = max(length(theta), length(r))
rmin, rmax = r_extrema
x, y = zeros(n), zeros(n)
for i in 1:n
x[i] = _cycle(r,i) * cos.(_cycle(phi,i))
y[i] = _cycle(r,i) * sin.(_cycle(phi,i))
x[i] = _cycle(theta, i)
y[i] = _cycle(r, i)
end
points = map((a, b) -> (a, b), x, y)
filter!(a -> a[2] >= rmin && a[2] <= rmax, points)
x = map(a -> a[1], points)
y = map(a -> a[2], points)
x, y
end
@@ -369,12 +409,12 @@ function fakedata(sz...)
y
end
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
isijulia() = :IJulia in nameof.(collect(values(Base.loaded_modules)))
isatom() = :Atom in nameof.(collect(values(Base.loaded_modules)))
function is_installed(pkgstr::AbstractString)
try
Pkg.installed(pkgstr) === nothing ? false: true
Pkg.installed(pkgstr) === nothing ? false : true
catch
false
end
@@ -396,20 +436,20 @@ isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.d)
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
ticksType{T<:AVec,S<:AVec}(ticks::Tuple{T,S}) = :ticks_and_labels
ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
ticksType(ticks::AVec{T}) where {T<:AbstractString} = :labels
ticksType(ticks::Tuple{T,S}) where {T<:AVec,S<:AVec} = :ticks_and_labels
ticksType(ticks) = :invalid
limsType{T<:Real,S<:Real}(lims::Tuple{T,S}) = :limits
limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng]
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = 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)))
@@ -480,16 +520,44 @@ function make_fillrange_from_ribbon(kw::KW)
y, rib = kw[:y], kw[:ribbon]
rib = wraptuple(rib)
rib1, rib2 = -first(rib), last(rib)
kw[:ribbon] = nothing
# kw[:ribbon] = nothing
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
(get(kw, :fillalpha, nothing) == nothing) && (kw[:fillalpha] = 0.5)
end
#turn tuple of fillranges to one path
function concatenate_fillrange(x,y::Tuple)
rib1, rib2 = first(y), last(y)
yline = vcat(rib1,(rib2)[end:-1:1])
xline = vcat(x,x[end:-1:1])
return xline, yline
end
function get_sp_lims(sp::Subplot, letter::Symbol)
axis_limits(sp[Symbol(letter, :axis)])
end
"""
xlims([plt])
Returns the x axis limits of the current plot or subplot
"""
xlims(sp::Subplot) = get_sp_lims(sp, :x)
"""
ylims([plt])
Returns the y axis limits of the current plot or subplot
"""
ylims(sp::Subplot) = get_sp_lims(sp, :y)
"""
zlims([plt])
Returns the z axis limits of the current plot or subplot
"""
zlims(sp::Subplot) = get_sp_lims(sp, :z)
xlims(plt::Plot, sp_idx::Int = 1) = xlims(plt[sp_idx])
ylims(plt::Plot, sp_idx::Int = 1) = ylims(plt[sp_idx])
zlims(plt::Plot, sp_idx::Int = 1) = zlims(plt[sp_idx])
@@ -497,6 +565,136 @@ xlims(sp_idx::Int = 1) = xlims(current(), sp_idx)
ylims(sp_idx::Int = 1) = ylims(current(), sp_idx)
zlims(sp_idx::Int = 1) = zlims(current(), sp_idx)
function get_clims(sp::Subplot)
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface)
for series in series_list(sp)
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Real)
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals.surf)...)
elseif (vals != nothing) && (eltype(vals) <: Real)
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...)
end
end
end
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
return zmin < zmax ? (zmin, zmax) : (-0.1, 0.1)
end
_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax)
function hascolorbar(series::Series)
st = series[:seriestype]
hascbar = st == :heatmap
if st == :contour
hascbar = (isscalar(series[:levels]) ? (series[:levels] > 1) : (length(series[:levels]) > 1)) && (length(unique(Array(series[:z]))) > 1)
end
if series[:marker_z] != nothing || series[:line_z] != nothing || series[:fill_z] != nothing
hascbar = true
end
# no colorbar if we are creating a surface LightSource
if xor(st == :surface, series[:fill_z] != nothing)
hascbar = true
end
return hascbar
end
function hascolorbar(sp::Subplot)
cbar = sp[:colorbar]
hascbar = false
if cbar != :none
for series in series_list(sp)
if hascolorbar(series)
hascbar = true
end
end
end
hascbar
end
function get_linecolor(series, i::Int = 1)
lc = series[:linecolor]
lz = series[:line_z]
if lz == nothing
isa(lc, ColorGradient) ? lc : plot_color(_cycle(lc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(lc, ColorGradient) ? lc : cgrad()
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
function get_linealpha(series, i::Int = 1)
_cycle(series[:linealpha], i)
end
function get_linewidth(series, i::Int = 1)
_cycle(series[:linewidth], i)
end
function get_linestyle(series, i::Int = 1)
_cycle(series[:linestyle], i)
end
function get_fillcolor(series, i::Int = 1)
fc = series[:fillcolor]
fz = series[:fill_z]
if fz == nothing
isa(fc, ColorGradient) ? fc : plot_color(_cycle(fc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(fc, ColorGradient) ? fc : cgrad()
grad[clamp((_cycle(fz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
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
for letter in (:x, :y, :z)
# If we have NaNs in the data they define the segments and
# SegmentsIterator is used
series[letter] != nothing && NaN in collect(series[letter]) && return false
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, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z, :marker_z))
end
# ---------------------------------------------------------------
makekw(; kw...) = KW(kw)
@@ -523,7 +721,7 @@ allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
"""
Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example:
```
with(:gadfly, size=(400,400), type=:histogram) do
with(:gr, size=(400,400), type=:histogram) do
plot(rand(10))
plot(rand(10))
end
@@ -608,7 +806,7 @@ end
# ---------------------------------------------------------------
# ---------------------------------------------------------------
type DebugMode
mutable struct DebugMode
on::Bool
end
const _debugMode = DebugMode(false)
@@ -646,17 +844,17 @@ 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{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
extendSeriesData{T}(v::AVec{T}, z::AVec) = (append!(v, convert(Vector{T}, z)); v)
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)
# -------------------------------------------------------
# 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
@@ -667,14 +865,14 @@ function getxyz(plt::Plot, i::Integer)
tovec(d[:x]), tovec(d[:y]), tovec(d[:z])
end
function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.series_list[i]
series.d[:x], series.d[:y] = xy
sp = series.d[:subplot]
reset_extrema!(sp)
_series_updated(plt, series)
end
function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z}
series = plt.series_list[i]
series.d[:x], series.d[:y], series.d[:z] = xyz
sp = series.d[:subplot]
@@ -682,7 +880,7 @@ function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
_series_updated(plt, series)
end
function setxyz!{X,Y,Z<:AbstractMatrix}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z<:AbstractMatrix}
setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i)
end
@@ -691,8 +889,8 @@ end
# indexing notation
# Base.getindex(plt::Plot, i::Integer) = getxy(plt, i)
Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = (setxy!(plt, xy, i); plt)
Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = (setxyz!(plt, xyz, i); plt)
Base.setindex!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y} = (setxy!(plt, xy, i); plt)
Base.setindex!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z} = (setxyz!(plt, xyz, i); plt)
# -------------------------------------------------------
@@ -732,7 +930,7 @@ function attr!(series::Series; kw...)
if haskey(_series_defaults, k)
series[k] = v
else
warn("unused key $k in series attr")
@warn("unused key $k in series attr")
end
end
_series_updated(series[:subplot].plt, series)
@@ -746,7 +944,7 @@ function attr!(sp::Subplot; kw...)
if haskey(_subplot_defaults, k)
sp[k] = v
else
warn("unused key $k in subplot attr")
@warn("unused key $k in subplot attr")
end
end
sp
@@ -804,10 +1002,10 @@ function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec, z::AVec)
end
# tuples
Base.push!{X,Y}(plt::Plot, xy::Tuple{X,Y}) = push!(plt, 1, xy...)
Base.push!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}) = push!(plt, 1, xyz...)
Base.push!{X,Y}(plt::Plot, i::Integer, xy::Tuple{X,Y}) = push!(plt, i, xy...)
Base.push!{X,Y,Z}(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) = push!(plt, i, xyz...)
Base.push!(plt::Plot, xy::Tuple{X,Y}) where {X,Y} = push!(plt, 1, xy...)
Base.push!(plt::Plot, xyz::Tuple{X,Y,Z}) where {X,Y,Z} = push!(plt, 1, xyz...)
Base.push!(plt::Plot, i::Integer, xy::Tuple{X,Y}) where {X,Y} = push!(plt, i, xy...)
Base.push!(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) where {X,Y,Z} = push!(plt, i, xyz...)
# -------------------------------------------------------
# push/append for all series
@@ -877,3 +1075,146 @@ xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series
"Extrema of x-values in plot"
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
# ---------------------------------------------------------------
# get fonts from objects:
titlefont(sp::Subplot) = font(
sp[:titlefontfamily],
sp[:titlefontsize],
sp[:titlefontvalign],
sp[:titlefonthalign],
sp[:titlefontrotation],
sp[:titlefontcolor],
)
legendfont(sp::Subplot) = font(
sp[:legendfontfamily],
sp[:legendfontsize],
sp[:legendfontvalign],
sp[:legendfonthalign],
sp[:legendfontrotation],
sp[:legendfontcolor],
)
tickfont(ax::Axis) = font(
ax[:tickfontfamily],
ax[:tickfontsize],
ax[:tickfontvalign],
ax[:tickfonthalign],
ax[:tickfontrotation],
ax[:tickfontcolor],
)
guidefont(ax::Axis) = font(
ax[:guidefontfamily],
ax[:guidefontsize],
ax[:guidefontvalign],
ax[:guidefonthalign],
ax[:guidefontrotation],
ax[:guidefontcolor],
)
# ---------------------------------------------------------------
# converts unicode scientific notation unsupported by pgfplots and gr
# into a format that works
function convert_sci_unicode(label::AbstractString)
unicode_dict = Dict(
'⁰' => "0",
'¹' => "1",
'²' => "2",
'³' => "3",
'⁴' => "4",
'⁵' => "5",
'⁶' => "6",
'⁷' => "7",
'⁸' => "8",
'⁹' => "9",
'⁻' => "-",
"×10" => "×10^{",
)
for key in keys(unicode_dict)
label = replace(label, key => unicode_dict[key])
end
if occursin("10^{", label)
label = string(label, "}")
end
label
end
function straightline_data(series)
sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))
x, y = series[:x], series[:y]
n = length(x)
if n == 2
return straightline_data(xl, yl, x, y)
else
k, r = divrem(n, 3)
if r == 0
xdata, ydata = fill(NaN, n), fill(NaN, n)
for i in 1:k
inds = (3 * i - 2):(3 * i - 1)
xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds])
end
return xdata, ydata
else
error("Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n")
end
end
end
function straightline_data(xl, yl, x, y)
x_vals, y_vals = if y[1] == y[2]
if x[1] == x[2]
error("Two identical points cannot be used to describe a straight line.")
else
[xl[1], xl[2]], [y[1], y[2]]
end
elseif x[1] == x[2]
[x[1], x[2]], [yl[1], yl[2]]
else
# get a and b from the line y = a * x + b through the points given by
# the coordinates x and x
b = y[1] - (y[1] - y[2]) * x[1] / (x[1] - x[2])
a = (y[1] - y[2]) / (x[1] - x[2])
# get the data values
xdata = [clamp(x[1] + (x[1] - x[2]) * (ylim - y[1]) / (y[1] - y[2]), xl...) for ylim in yl]
xdata, a .* xdata .+ b
end
# expand the data outside the axis limits, by a certain factor too improve
# plotly(js) and interactive behaviour
factor = 100
x_vals = x_vals .+ (x_vals[2] - x_vals[1]) .* factor .* [-1, 1]
y_vals = y_vals .+ (y_vals[2] - y_vals[1]) .* factor .* [-1, 1]
return x_vals, y_vals
end
function shape_data(series)
sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))
x, y = series[:x], series[:y]
factor = 100
for i in eachindex(x)
if x[i] == -Inf
x[i] = xl[1] - factor * (xl[2] - xl[1])
elseif x[i] == Inf
x[i] = xl[2] + factor * (xl[2] - xl[1])
end
end
for i in eachindex(y)
if y[i] == -Inf
y[i] = yl[1] - factor * (yl[2] - yl[1])
elseif y[i] == Inf
y[i] = yl[2] + factor * (yl[2] - yl[1])
end
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
+2 -3
View File
@@ -1,10 +1,9 @@
StatPlots
FactCheck
Images
ImageMagick
@osx QuartzImageIO
GR
GR 0.31.0
RDatasets
VisualRegressionTests
UnicodePlots
Glob
LaTeXStrings
+14 -18
View File
@@ -2,21 +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 FactCheck
using Glob
# using StatPlots
using Test
default(size=(500,300))
@@ -24,18 +23,18 @@ 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.12.0"
const _current_plots_version = v"0.17.4"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
Plots._debugMode.on = debug
example = Plots._examples[idx]
info("Testing plot: $pkg:$idx:$(example.header)")
@info("Testing plot: $pkg:$idx:$(example.header)")
backend(pkg)
backend()
# ensure consistent results
srand(1234)
Random.seed!(1234)
# reference image directory setup
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
@@ -43,11 +42,8 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
fn = "ref$idx.png"
# firgure out version info
G = glob(joinpath(relpath(refdir), "*"))
# @show refdir fn G
slash = (@static is_windows() ? "\\" : "/")
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
versions = reverse(sort(versions))
vns = filter(x->x[1] != '.', readdir(refdir))
versions = sort(VersionNumber.(vns), rev = true)
versions = filter(v -> v <= _current_plots_version, versions)
# @show refdir fn versions
@@ -99,7 +95,7 @@ function image_comparison_facts(pkg::Symbol;
for i in 1:length(Plots._examples)
i in skip && continue
if only == nothing || i in only
@fact @eval(image_comparison_tests(Symbol(String(Symbol($pkg))[7:end]), $i, debug=$debug, sigma=$sigma, eps=$eps)) |> success --> true
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
end
end
end
+2 -2
View File
@@ -6,8 +6,8 @@ sudo apt-get -qq update
# sudo apt-get install -y wkhtmltopdf
sudo apt-get install -y xfonts-75dpi xfonts-base
wget https://downloads.wkhtmltopdf.org/0.12/0.12.2/wkhtmltox-0.12.2_linux-precise-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2_linux-precise-amd64.deb
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb
# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
# sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
wkhtmltoimage http://www.google.com test.png
+52 -49
View File
@@ -3,41 +3,43 @@ module PlotsTests
include("imgcomp.jl")
# don't actually show the plots
srand(1234)
Random.seed!(1234)
default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2
facts("GR") do
@fact gr() --> Plots.GRBackend()
@fact backend() --> Plots.GRBackend()
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@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
facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
#@testset "PyPlot" begin
# @test pyplot() == Plots.PyPlotBackend()
# @test backend() == Plots.PyPlotBackend()
#
# image_comparison_facts(:pyplot, eps=img_eps)
#end
image_comparison_facts(:pyplot, eps=img_eps)
end
facts("UnicodePlots") do
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
@fact backend() --> Plots.UnicodePlotsBackend()
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
# lets just make sure it runs without error
@fact isa(plot(rand(10)), Plots.Plot) --> true
@test isa(plot(rand(10)), Plots.Plot) == true
end
# The plotlyjs testimages return a connection error on travis:
# connect: connection refused (ECONNREFUSED)
# facts("PlotlyJS") do
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
# @fact backend() --> Plots.PlotlyJSBackend()
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# if is_linux() && isinteractive()
# if Sys.islinux() && isinteractive()
# image_comparison_facts(:plotlyjs,
# skip=[
# 2, # animation (skipped for speed)
@@ -53,9 +55,9 @@ end
# ERROR: LoadError: InitError: Cannot open display:
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
# facts("InspectDR") do
# @fact inspectdr() --> Plots.InspectDRBackend()
# @fact backend() --> Plots.InspectDRBackend()
# @testset "InspectDR" begin
# @test inspectdr() == Plots.InspectDRBackend()
# @test backend() == Plots.InspectDRBackend()
#
# image_comparison_facts(:inspectdr,
# skip=[
@@ -72,41 +74,41 @@ end
# end
# facts("Plotly") do
# @fact plotly() --> Plots.PlotlyBackend()
# @fact backend() --> Plots.PlotlyBackend()
# @testset "Plotly" begin
# @test plotly() == Plots.PlotlyBackend()
# @test backend() == Plots.PlotlyBackend()
#
# # # until png generation is reliable on OSX, just test on linux
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
# # @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
# facts("Immerse") do
# @fact immerse() --> Plots.ImmerseBackend()
# @fact backend() --> Plots.ImmerseBackend()
# @testset "Immerse" begin
# @test immerse() == Plots.ImmerseBackend()
# @test backend() == Plots.ImmerseBackend()
#
# # as long as we can plot anything without error, it should be the same as Gadfly
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
# end
# facts("PlotlyJS") do
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
# @fact backend() --> Plots.PlotlyJSBackend()
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# # as long as we can plot anything without error, it should be the same as Plotly
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
# end
# facts("Gadfly") do
# @fact gadfly() --> Plots.GadflyBackend()
# @fact backend() --> Plots.GadflyBackend()
# @testset "Gadfly" begin
# @test gadfly() == Plots.GadflyBackend()
# @test backend() == Plots.GadflyBackend()
#
# @fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
# @fact plot(Int[1,2,3], rand(3)) --> not(nothing)
# @fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
# @fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
#
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# end
@@ -114,24 +116,27 @@ end
facts("Axes") do
@testset "Axes" begin
p = plot()
axis = p.subplots[1][:xaxis]
@fact typeof(axis) --> Plots.Axis
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
@fact Plots.ignorenan_extrema(axis) --> (0.5,1.5)
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
@test typeof(axis) == Plots.Axis
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
@test Plots.ignorenan_extrema(axis) == (0.5,1.5)
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
Plots.discrete_value!(axis, ["x$i" for i=1:5])
Plots.discrete_value!(axis, ["x$i" for i=0:2])
@fact Plots.ignorenan_extrema(axis) --> (0.5, 7.5)
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
end
@testset "NoFail" begin
histogram([1, 0, 0, 0, 0, 0])
end
# tests for preprocessing recipes
# facts("recipes") do
# @testset "recipes" begin
# user recipe
@@ -168,6 +173,4 @@ end
# end
FactCheck.exitstatus()
end # module
+10 -7
View File
@@ -1,15 +1,18 @@
using Pkg
Pkg.add("ImageMagick")
Pkg.build("ImageMagick")
Pkg.clone("GR")
Pkg.build("GR")
# Pkg.clone("GR")
# Pkg.build("GR")
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
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")