Compare commits

...

168 Commits

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