Compare commits

...

386 Commits

Author SHA1 Message Date
Daniel Schwabeneder 64e035c53c Merge pull request #2090 from daschw/areaplot
add areaplot recipe (close #1423)
2019-07-04 13:45:52 +02:00
Daniel Schwabeneder adbe515af7 up version 2019-07-04 12:55:02 +02:00
Daniel Schwabeneder f0dac1630f fewer lines 2019-07-04 12:53:01 +02:00
Daniel Schwabeneder ddaa69bce2 move areaplot doc from shorthands to recipes 2019-07-04 12:48:47 +02:00
Daniel Schwabeneder bb7c2fd660 Merge pull request #2089 from daschw/zcolor-missing
allow missing in line_z, fill_z and marker_z (fix #2083)
2019-07-04 11:36:08 +02:00
Daniel Schwabeneder 8dfca61769 add areaplot recipe 2019-07-04 11:31:00 +02:00
Daniel Schwabeneder bb3c54cb27 allow missing in line_z, fill_z and marker_z 2019-07-04 10:39:31 +02:00
Daniel Schwabeneder 2816b1128f Merge pull request #2081 from oschulz/loghist-zerobins-fix
Fix representation of zero-valued bins on step-histograms with log-y axis
2019-07-02 08:01:50 +02:00
Daniel Schwabeneder cf0cf972e3 Merge pull request #2080 from daschw/gr-linealpha
fix gr linealpha (fix #2078)
2019-07-02 08:01:23 +02:00
Daniel Schwabeneder bb0e783c02 Merge pull request #2082 from yha/point-recipe-fix
Support arbitrary element type (esp. missing) in tuple/Point recipes
2019-07-01 22:02:52 +02:00
yha a7b7c5ba81 Support any element type (incl. missing) and length in tuple/Point recipes 2019-07-01 01:39:05 +03:00
Oliver Schulz 7214b8b1b1 Improve type stability of _stepbins_path 2019-06-30 17:42:25 +02:00
Oliver Schulz db1e25252a Fix zero and NaN weighted bins in stephist for log-yscale
Bins with weight NaN and zero (which the Plots engine seems to
turn into into NaN automatically for log-yscale) should
not be draws in log-yscale.
2019-06-30 17:42:25 +02:00
Daniel Schwabeneder 7a248331e7 fix gr linealpha 2019-06-30 13:15:04 +02:00
Daniel Schwabeneder 161ffdee94 Merge pull request #2076 from daschw/register
up version
2019-06-27 11:37:28 +02:00
Daniel Schwabeneder b3e8fd9c66 up version 2019-06-27 11:36:12 +02:00
Michael Krabbe Borregaard 538135bc5f Merge pull request #2075 from yha/missing-in-matrix
Fix handling of missing values in matrix inputs.
2019-06-27 11:22:35 +02:00
yha 0aac0398e8 Fix handling of missing values in matrix inputs. 2019-06-27 01:23:26 +03:00
Daniel Schwabeneder 552024ff31 Merge pull request #2074 from daschw/pyplot-gradient
allow specifying the color gradient for z values in pyplot (fix #2041)
2019-06-26 15:17:59 +02:00
Daniel Schwabeneder 2f14c37c59 remove unnecessary lines 2019-06-26 13:04:14 +02:00
Daniel Schwabeneder 7f8dc486bb allow specifying the color gradient for z values in pyplot 2019-06-26 12:09:59 +02:00
Daniel Schwabeneder a89b42229a Merge pull request #2067 from yha/max-bins
Limit number of automatic bins
2019-06-25 13:55:30 +02:00
Michael Krabbe Borregaard e061d156bc Merge pull request #2069 from JeffFessler/patch-1
Document :colorbar_entry
2019-06-21 16:19:27 +02:00
Jeff Fessler 8f4753a0bb Document :colorbar_entry
Addresses #2068
2019-06-21 09:53:22 -04:00
yha b3336229ab Limit number of automatic bins 2019-06-17 01:31:08 +03:00
Daniel Schwabeneder 80c1cb954d Merge pull request #2065 from daschw/default-backend
fix ENV["PLOTS_DEFAULT_BACKEND"] (fix #1942)
2019-06-15 20:34:32 +02:00
Daniel Schwabeneder 0f6336b3dd fix ENV['PLOTS_DEFAULT_BACKEND'] 2019-06-15 18:30:21 +02:00
Daniel Schwabeneder cd1ee47ace Merge pull request #2061 from daschw/ratio
don't let aspect_ratio impact subplot size
2019-06-14 17:36:54 +02:00
Daniel Schwabeneder 46ed2f6263 fix pgfplots axis limits 2019-06-13 23:12:12 +02:00
Daniel Schwabeneder 63f6128c87 respect user lims 2019-06-13 23:03:19 +02:00
Daniel Schwabeneder 9f9ac4ec92 bbox_ratio not required 2019-06-13 18:50:59 +02:00
Michael Krabbe Borregaard 7cf223a5b8 Merge pull request #2063 from yha/segments-fix
Fix SegmentsIterator for more than one initial NaN
2019-06-13 16:07:58 +02:00
yha 589643d591 Fix SegmentsIterator for more than one initial NaN. 2019-06-13 16:44:05 +03:00
Daniel Schwabeneder 3509648553 Merge pull request #2049 from yha/pyplot-hide-axis
Fix hiding of axis on PyPlot
2019-06-12 23:12:02 +02:00
Daniel Schwabeneder 94841669bf Merge pull request #2060 from daschw/gr_arrow
Implement arrowstyle for GR (fix #2059)
2019-06-12 23:02:12 +02:00
Daniel Schwabeneder fadc0bf6c7 don't let aspect_ratio impact subplot size 2019-06-12 22:49:12 +02:00
Daniel Schwabeneder fd2c01808a add :open and :closed arrow 2019-06-12 19:26:15 +02:00
Daniel Schwabeneder 8342da1ea2 allow row vector of arrows 2019-06-11 23:15:59 +02:00
Daniel Schwabeneder e9abb6d021 implement arrowstyle for GR 2019-06-11 22:55:54 +02:00
Michael Krabbe Borregaard 505989eec7 Merge pull request #2052 from marekkukan-tw/mk/fixplotly
fix bug in plotly_convert_to_datetime
2019-06-08 09:47:02 +02:00
Marek Kukan 08a30b255d fix bug in plotly_convert_to_datetime 2019-06-06 14:31:54 +02:00
Michael Krabbe Borregaard 1543c77a39 Merge pull request #2051 from yha/first-missing
Fix for missing as first element
2019-06-04 20:47:10 +02:00
yha 4c22a421a1 No error when input is all missing 2019-06-04 21:00:52 +03:00
yha 972c97d5ec Fix for missing as first element 2019-06-04 20:51:03 +03:00
yha fd611b3647 Fix hiding of axis on PyPlot 2019-06-03 20:22:44 +03:00
Josef Heinen 71cbaa843c gr: added support for polar heatmaps 2019-06-03 02:25:16 -07:00
Michael Krabbe Borregaard bbf8b50ad6 Merge pull request #2043 from yha/colorbar-warn-less
Only warn for series sharing a colorbar when it matters.
2019-06-02 19:30:00 +02:00
yha ddd083b8c1 Fix for gr_get_color(series) == nothing 2019-06-02 19:21:31 +03:00
yha 03f6c76b53 Only warn for series sharing a colorbar when it matters. 2019-05-30 19:08:19 +03:00
Daniel Schwabeneder 0735a3475c Merge pull request #2031 from fredrikekre/fe/show-return
Make sure show return nothing.
2019-05-17 12:46:17 +02:00
Fredrik Ekre 9a445d529d Make sure show return nothing. 2019-05-17 10:41:01 +02:00
Daniel Schwabeneder 1ea5a5ac0b Merge pull request #2029 from daschw/register
up version
2019-05-13 22:17:04 +02:00
Daniel Schwabeneder bc8370eadd update NEWS.md 2019-05-13 22:16:18 +02:00
Daniel Schwabeneder cdc5a2b361 up version 2019-05-13 22:13:27 +02:00
Daniel Schwabeneder 4270ac80fb Merge pull request #2028 from shipengcheng1230/master
fix gr_display (close #2026)
2019-05-12 19:34:32 +02:00
shipengcheng1230 405df5da8b fix gr_display 2019-05-12 13:14:03 -04:00
Daniel Schwabeneder f742ae4c88 Merge pull request #2025 from daschw/registrator
add author and version to Project.toml
2019-05-10 17:55:17 +02:00
Daniel Schwabeneder a99783dfa0 add author and version 2019-05-10 17:45:56 +02:00
Daniel Schwabeneder 9af5edd04d Merge pull request #2022 from JuliaPlots/sd-toml
use Project.toml + clean up test deps
2019-05-10 17:39:45 +02:00
SimonDanisch d0830b90be remove PlotReferenceImages 2019-05-09 13:06:05 +02:00
SimonDanisch 8cd48bc660 add back tomls 2019-05-09 13:01:49 +02:00
SimonDanisch 379a320d2d remove debug 2019-05-09 12:45:13 +02:00
SimonDanisch d5f3a3ef69 clean up & fix tests 2019-05-09 12:40:19 +02:00
SimonDanisch a3be970f29 get around registered PLotReferenceImages by downloading source of tags 2019-05-09 11:48:40 +02:00
SimonDanisch 63f8f52c9f remove REQUIRES 2019-05-09 11:06:22 +02:00
SimonDanisch 169851564c use Project.toml + clean up test deps 2019-05-08 17:23:36 +02:00
Daniel Schwabeneder c32b9029d1 Merge pull request #2016 from H-M-H/pgf_axis_arrows
Add attribute draw_arrow for axes.
2019-05-06 22:20:52 +02:00
Daniel Schwabeneder 3fe60b9d18 Merge pull request #2018 from daschw/legend
outer legends for gr and pyplot and guide/margin improvements for gr
2019-05-05 16:24:07 +02:00
Daniel Schwabeneder 34cff752f1 missing method for gr_set_transparency 2019-05-05 13:22:16 +02:00
Daniel Schwabeneder 0dba83daf6 fix gr alphas 2019-05-05 13:08:03 +02:00
Daniel Schwabeneder c399092261 fix animations for pyplot 2019-05-04 20:43:49 +02:00
Daniel Schwabeneder dcabb2c579 ticks, guides, margins for gr 2019-05-02 23:04:35 +02:00
Daniel Schwabeneder 3542785021 Merge pull request #2017 from daschw/recipe
fix recipe error
2019-05-02 16:13:47 +02:00
Daniel Schwabeneder 65173e6dd2 fix recipe error 2019-05-02 12:48:06 +02:00
Daniel Schwabeneder bf0bb68e28 only add half of ticks text size to min padding 2019-05-02 11:31:20 +02:00
Daniel Schwabeneder 21774dc36b consider rotation in gr_get_ticks_size 2019-05-02 11:27:16 +02:00
Daniel Schwabeneder 0e3a9f0b8f outer legends for GR 2019-05-02 11:18:17 +02:00
Daniel Schwabeneder 903cb404c3 shorter implementation 2019-05-01 12:12:51 +02:00
Daniel Schwabeneder 03325533bf outer legend positions for pyplot 2019-05-01 12:08:35 +02:00
HMH 710123aab4 Add attribute draw_arrow for axes.
The draw_arrow attribute enables drawing an arrow at the end of an axis.
Currently supported only by the PGFPlots backend.
2019-05-01 00:27:20 +02:00
Daniel Schwabeneder 4742ec972b allow numeric legend positioning in pyplot 2019-04-30 15:25:08 +02:00
Michael Krabbe Borregaard e860ba220a Merge pull request #2011 from 8uurg/master
Make legend=:outertopright work for GR
2019-04-29 08:26:36 +02:00
8uurg 39605bccc2 Make legend=:outertopright work
Move x to the right of the plot viewport
Perform legend size computation earlier as this computed width is required for adjusting the width of the plotarea viewport.
This adjustment has to be done before any further computations requiring this plotarea viewport width.
2019-04-27 20:13:36 +02:00
Daniel Schwabeneder 1a4f411b8f Merge pull request #2010 from daschw/polar
Avoid filtering data in polar plots (fix #2009)
2019-04-26 18:45:12 +02:00
Daniel Schwabeneder a6588daa3e allow negative radii in polar plots for pyplot 2019-04-26 13:17:29 +02:00
Daniel Schwabeneder b053366b06 don't filter polar data 2019-04-26 13:03:03 +02:00
Michael Krabbe Borregaard e838ac502d Merge pull request #1999 from mkborregaard/fix_io
[RFC] fix io; close #1998
2019-04-15 15:16:41 +02:00
Michael Krabbe Borregaard 6131154dd0 mixing ios in println 2019-04-15 15:13:22 +02:00
Michael Krabbe Borregaard 0c67a61e7d fix io 2019-04-15 09:07:52 +02:00
Daniel Schwabeneder 72696a4326 Merge pull request #1995 from daschw/marker
don't let `marker = true` set the marker size to 1 (fix #1994)
2019-04-12 14:12:40 +02:00
Daniel Schwabeneder 3231f4d9b1 Merge pull request #1996 from daschw/line
sort vector attributes for seriestype line (fix #1989)
2019-04-12 14:02:04 +02:00
Daniel Schwabeneder 8a81b398cf fix typo 2019-04-12 12:44:34 +02:00
Daniel Schwabeneder a37a1a0004 sort vector attributes for seriestype line 2019-04-12 12:41:49 +02:00
Daniel Schwabeneder b6b00c843a set default to :circle instead of :auto for marker = true 2019-04-12 09:42:19 +02:00
Daniel Schwabeneder 5506c0543c don't let marker = true set the marker size to 1 2019-04-12 09:24:28 +02:00
Michael Krabbe Borregaard 7a1b48311c Merge pull request #1993 from mkborregaard/fix_plotattr
fix plotattr
2019-04-10 10:09:15 +02:00
Michael Krabbe Borregaard 0b3dafcd18 fix plotattr
`plotattr` would fail when the description did not have a period (`.`) in it, e.g. for `ticks`. This seemed safer than to edit the argument descriptions
2019-04-09 21:16:56 +02:00
Daniel Schwabeneder 81f6b3c7bd Merge pull request #1986 from daschw/geometrytypes
replace StaticArrays with GeometryTypes (fix #1886)
2019-04-08 12:46:57 +02:00
Daniel Schwabeneder c2da4acb48 update news 2019-04-07 16:23:26 +02:00
Daniel Schwabeneder 841b05631d replace StaticArrays with GeometryTypes 2019-04-07 16:20:15 +02:00
Daniel Schwabeneder a6e60aea04 Merge pull request #1982 from daschw/colorvector
fix passing a vector of colors
2019-04-04 14:23:18 +02:00
Daniel Schwabeneder 7f2a1db64a fix passing a vector of colors 2019-04-04 11:26:12 +02:00
Daniel Schwabeneder 926ccdf618 Merge pull request #1977 from daschw/colorbar-alpha
fix alpha for colorbar in GR (fix #1976)
2019-04-02 21:55:49 +02:00
Josef Heinen 9774eca8e2 bump GR version to 0.39.0 2019-04-02 20:55:51 +02:00
Josef Heinen 2ad033f8e2 Merge pull request #1978 from jheinen/master
gr: use correct workstation type after savefig()
2019-04-01 14:18:51 +02:00
Josef Heinen 7c26ffee51 gr: use correct workstation type after savefig() 2019-04-01 14:05:32 +02:00
Daniel Schwabeneder aa37ba0463 Merge pull request #1970 from SebRollen/master
Update `yaxis!` description
2019-04-01 13:16:50 +02:00
Daniel Schwabeneder d61c86b54b fix alpha for colorbar in GR 2019-04-01 13:14:06 +02:00
Daniel Schwabeneder e72fa1dc74 Merge pull request #1971 from daschw/grid-ticks
don't draw ticks twice in gr for framestyle in (:zerolines, :grid)
2019-04-01 10:03:45 +02:00
Michael Krabbe Borregaard 16db531cce Merge pull request #1969 from yha/contour-colorbar
Some more fixes for contours and colorbars (mostly GR)
2019-04-01 09:52:56 +02:00
Michael Krabbe Borregaard 226023043b Merge pull request #1972 from hycakir/patch-1
fix `abline!` description
2019-03-30 12:16:35 +01:00
Hamza Yusuf Çakır 5d2538c4c2 fix abline! description
It should be `ax+b` rather than `a+bx`.
2019-03-30 12:09:17 +03:00
yharel 0075103ddf Proportional colorbar spacing in pyplot 2019-03-29 22:01:28 +03:00
yharel 8982a67902 Fix colorbar for misc. series types with line_z,fill_z,marker_z. 2019-03-29 21:20:36 +03:00
Daniel Schwabeneder 65ab45ff1b don't draw ticks twice in gr for framestyle in (:zerolines, :grid) 2019-03-29 10:38:22 +01:00
Sebastian Rollen 577d434bc8 Update yaxis! description
Just fixing a small typo. The description for `yaxis!` used to read "Specify x axis attributes for an existing plot", changed to "Specify y axis attributes for an existing plot"
2019-03-28 09:54:23 -04:00
Daniel Schwabeneder b300e634f6 Merge pull request #1968 from daschw/ticks
fix multiple drawing of discrete ticks
2019-03-28 09:24:46 +01:00
Josef Heinen 61d13b9b2d gr: improved positioning of Y labels 2019-03-28 08:39:15 +01:00
yharel 78059bf825 Support for non-gradient colors in surface-like plots (useful for contour) 2019-03-28 02:28:19 +02:00
yharel dd02a69e8f Consistent interpretation of contour levels across PyPlot,GR,Plotly[JS] backends.
GR: fixed colorbar rendering/alignment for contour[f]. Merged colorbar 
for mutiple series.
:colorbar_entry property to include series in colorbar.
2019-03-28 02:21:25 +02:00
Daniel Schwabeneder 5ec80ad1f1 fix multiple drawing of discrete ticks 2019-03-27 17:37:47 +01:00
Josef Heinen 4849772435 gr: improve Y label alignment 2019-03-26 14:30:14 +01:00
Daniel Schwabeneder 6546879d3a Merge pull request #1963 from daschw/init
fix init error if PLOTS_DEFAULTS <: Dict{Symbol, Symbol} (fix #1962)
2019-03-26 09:51:18 +01:00
Josef Heinen cbc379daa9 gr: fixed problem with blank figures
see https://github.com/jheinen/GR.jl/issues/202
2019-03-25 17:15:06 +01:00
Daniel Schwabeneder a7be08ef46 fix init error if PLOTS_DEFAULTS <: Dict{Symbol, Symbol} 2019-03-25 09:46:37 +01:00
Daniel Schwabeneder 47e48e5d27 Merge pull request #1958 from JuliaPlots/sd-gifmime
add support for gif mime
2019-03-25 09:35:25 +01:00
Daniel Schwabeneder 968b8109dd Merge pull request #1956 from daschw/pyplot-update
Pyplot API update (fix #1932)
2019-03-25 09:35:03 +01:00
SimonDanisch 19fba27951 don't read into a buffer first 2019-03-19 14:23:25 +01:00
SimonDanisch b78da20d04 add support for gif mime 2019-03-19 12:40:40 +01:00
Daniel Schwabeneder 5e445b4a71 update NEWS.md 2019-03-16 19:33:35 +01:00
Daniel Schwabeneder 0e5df883d0 add warning for PyCall version 2019-03-16 10:42:45 +01:00
Daniel Schwabeneder b79ea119ea use a.''foo'' instead of a.foo 2019-03-15 15:15:59 +01:00
Daniel Schwabeneder b21d98affd switch to new PyCall API 2019-03-15 15:13:57 +01:00
Daniel Schwabeneder d83666bed3 Merge pull request #1953 from daschw/polar-axis
put radius 0 at the center for polar plots (fix #1813)
2019-03-14 10:27:49 +01:00
Daniel Schwabeneder cab6ca3ef0 default to radius 0 at center for polar plots 2019-03-13 13:40:05 +01:00
Daniel Schwabeneder 33a37f9494 Merge pull request #1951 from daschw/gr-image
fix image axis limits
2019-03-13 09:37:02 +01:00
Daniel Schwabeneder 79e978aac9 fix image axis limits 2019-03-12 14:56:41 +01:00
Michael Krabbe Borregaard 3af60a81f8 Merge pull request #1950 from JuliaPlots/sd-plotlyjson
add plotly json mime to PlotlyBackend as well
2019-03-12 14:21:07 +01:00
SimonDanisch 56525ced92 also add plotly json mime to PlotlyBackend 2019-03-12 12:59:19 +01:00
Simon 581f3797bc Merge pull request #1943 from JuliaPlots/sd-plotlymime
support plotly mime type
2019-03-11 15:12:21 +01:00
SimonDanisch 2c8d51988b support plotly mime type 2019-03-07 19:04:18 +01:00
Daniel Schwabeneder 19243b741a Merge pull request #1939 from daschw/gr-ticks
fix `ticks = :none` for gr
2019-03-05 14:19:48 +01:00
Daniel Schwabeneder afc1e08f21 Merge pull request #1940 from daschw/plotly-flip
plotly: fix yflip for `ticks = :none` (fix #1937)
2019-03-05 14:19:33 +01:00
Daniel Schwabeneder 80c01e74c6 plotly: fix yflip for ticks = :none 2019-03-05 10:34:05 +01:00
Daniel Schwabeneder d728bfb90c don't show labels for ticks = :none 2019-03-05 10:01:06 +01:00
Daniel Schwabeneder 203d73ee26 fix ticks = :none for gr 2019-03-05 09:57:12 +01:00
Daniel Schwabeneder 05fe220102 Merge pull request #1936 from balazsmezei/pgfplots-tex-standalone
Add option :tex_output_standalone for standalone documentclass
2019-03-05 09:30:06 +01:00
Balázs Ferenc Mezei c4f2de198e Add option :tex_output_standalone to set the 'include_preamble' argument in the PGFPlots backend. 2019-03-03 00:04:05 +00:00
Michael Krabbe Borregaard 50f9846836 Merge pull request #1933 from JuliaPlots/new_pyplot
update to `o.show` syntax. Close #1932
2019-03-01 07:55:11 +01:00
Michael Krabbe Borregaard a33b3cfbd8 check for pycall version 2019-02-28 23:50:06 +01:00
Michael Krabbe Borregaard 248f7cce90 update to o.show syntax 2019-02-28 23:32:57 +01:00
Josef Heinen 8f381e2611 Merge pull request #1931 from apalugniok/gr-titles3d
Add 3D axes guides for GR (Fixes #743)
2019-02-27 12:25:18 +01:00
Andrew Palugniok f4b14d0d8d Add 3D axes guides for GR 2019-02-27 10:30:34 +00:00
Michael Krabbe Borregaard 93428815e4 Merge pull request #1924 from H-M-H/pgf_vline
Add vline to PGFPlots.
2019-02-23 10:19:42 +01:00
Michael Krabbe Borregaard 6b70610770 Merge pull request #1925 from H-M-H/pyplot_tex
Add LaTeX output for pyplot backend.
2019-02-23 10:10:58 +01:00
Michael Krabbe Borregaard 84eead47e3 Merge pull request #1926 from H-M-H/plotly_fix
Fix #1961
2019-02-23 10:08:06 +01:00
HMH 009d03f1f8 Set default output for plotly to html.
There does not exist any other.
2019-02-23 04:59:58 +01:00
HMH 9482a247e7 Remove 2 lines forgotten in 3c2cfa333c. 2019-02-23 03:39:01 +01:00
HMH 022c79fa95 Add LaTeX output for pyplot backend.
Actually matplotlib supports outputting LaTeX via pgf:
https://matplotlib.org/users/pgf.html
2019-02-23 00:35:52 +01:00
HMH a9ed4ac21d Add vline to PGFPlots.
This enables proper vertical errorbars.
2019-02-22 17:50:15 +01:00
Michael Krabbe Borregaard 354e39e9bf Merge pull request #1923 from harryscholes/fix-1918
plotlyjs: Fix custom tick labels do not work when supplied as a tuple
2019-02-21 21:08:01 +01:00
harryscholes 757e08c6fe Add Union{AVec,Tuple} to accepted types for ticksType 2019-02-21 17:59:27 +00:00
Josef Heinen 33e5775294 Merge pull request #1922 from jheinen/master
bump GR version to 0.38.1
2019-02-19 10:27:13 +01:00
Josef Heinen 5b73a8ed1c bump GR version to 0.38.1 2019-02-19 09:39:06 +01:00
Josef Heinen f864ebbf1a Merge remote-tracking branch 'upstream/master' 2019-02-18 20:24:09 +01:00
Michael Krabbe Borregaard 54b6051315 bump GR version 2019-02-18 11:37:15 +01:00
Michael Krabbe Borregaard ebea34920b Merge pull request #1919 from yha/colorbar-fixes
GR: contour colorbar fixes
2019-02-18 08:17:11 +01:00
yharel 44294306ce Using fillcolor for contour with fill=true.
Removed failed attempt at supporting single-color contours.
2019-02-18 04:50:16 +02:00
yharel c2af1a0666 Colorbar and contour fixes 2019-02-18 04:02:31 +02:00
Josef Heinen 8f30696a4d gr: added support for volume plots 2019-02-16 18:03:21 +01:00
Josef Heinen b58082a37b Merge remote-tracking branch 'upstream/master'
t push
2019-02-14 14:08:29 +01:00
Michael Krabbe Borregaard a594878860 Merge pull request #1915 from o01eg/fix-1904
Fix bar plot for unicode plots backend
2019-02-09 13:18:05 +01:00
O01eg 3a2b6296ac Fix UndefVarError: series not defined 2019-02-09 12:38:57 +03:00
O01eg 87af609a6f Add test case for https://github.com/JuliaPlots/Plots.jl/issues/1904 2019-02-09 12:25:02 +03:00
Josef Heinen a0d5d0f3c8 Merge remote-tracking branch 'upstream/master'
t push
2019-02-08 16:33:13 +01:00
Michael Krabbe Borregaard 53510f3268 Merge pull request #1910 from BioTurboNick/master
Fixed MethodError
2019-02-03 21:03:15 +01:00
Nicholas Bauer 9d5ce9753a Fixed MethodError 2019-02-03 14:19:32 -05:00
Josef Heinen d7a2df41fa t push
Merge remote-tracking branch 'upstream/master'
2019-01-29 08:56:04 +01:00
Michael Krabbe Borregaard f905cb9577 Merge pull request #1829 from oschulz/faster-load
Reduce load time for Plots and GR backend
2019-01-28 14:24:23 +01:00
Oliver Schulz b9b6439f47 Clean up backend default handling 2019-01-25 17:18:44 +01:00
Oliver Schulz ffcdf986a3 Set explicit return type for function _backend_instance
Inferred return type is Any, otherwise, not AbstractBackend.
2019-01-25 17:18:44 +01:00
Oliver Schulz 43245b5eb5 Clean up backend-related global vars and related functions 2019-01-25 17:18:44 +01:00
Oliver Schulz 420228c67b Remove function add_backend
No longer in use.
2019-01-25 17:18:44 +01:00
Oliver Schulz f1719d6e91 Improve implementation of backend(pkg::AbstractBackend) 2019-01-25 17:05:43 +01:00
Oliver Schulz 9aa1fd5c00 macro init_backend can call backend() with backend instance 2019-01-25 17:05:43 +01:00
Oliver Schulz 141845aa40 _initialize_backend doesn't need to do anything for PlotlyBackend 2019-01-25 17:05:43 +01:00
Oliver Schulz 7867df6079 _initialize_backend doesn't need to do anything for GRBackend 2019-01-25 17:05:43 +01:00
Oliver Schulz 182b937143 Refactor __init__() to make Plots load faster 2019-01-25 17:05:43 +01:00
Josef Heinen 5a54fb7e9f t push
Merge remote-tracking branch 'upstream/master'
2019-01-25 14:22:27 +01:00
Michael Krabbe Borregaard 399a9b16f6 StatPlots --> StatsPlots 2019-01-24 23:24:17 +01:00
Josef Heinen fef45dfc30 gr: clamp rgb values 2019-01-24 20:37:33 +01:00
Michael Krabbe Borregaard 42aa7d8d55 Merge pull request #1901 from mkborregaard/clamp
Inplace clamp
2019-01-23 22:36:00 +01:00
Michael Krabbe Borregaard 8778119792 Inplace clamp 2019-01-23 22:35:13 +01:00
Michael Krabbe Borregaard 10e3f2c990 Merge pull request #1900 from mkborregaard/clamp
WIP clamp greyscale images to (0,1)
2019-01-23 21:05:09 +01:00
Michael Krabbe Borregaard 5e25989366 copy and clamp for greyscale images if outside (0,1) 2019-01-23 21:04:27 +01:00
Michael Krabbe Borregaard f12d328cf7 clamp image for backends not supporting image
Does not work for GR or PyPlot which are supposed to support images natively
2019-01-23 21:04:27 +01:00
Daniel Schwabeneder efc4917724 Merge pull request #1769 from djsegal/djsegal/scatter
Allow vectors of markers for pyplot scatter
2019-01-23 19:21:05 +01:00
Daniel Schwabeneder c2bf145ff5 Merge pull request #1895 from sswatson/fontargs
Support keyword arguments for font options
2019-01-23 19:05:39 +01:00
djsegal c8c82811b3 Fix bug where pyplot marker vec added blank legend 2019-01-22 15:07:21 -05:00
Daniel Schwabeneder c21e133e69 Merge pull request #1899 from daschw/pyplot-image
fix grayscale image in pyplot
2019-01-22 13:55:43 +01:00
Daniel Schwabeneder 789a7fbb88 fix grayscale image in pyplot 2019-01-22 13:00:56 +01:00
Samuel S. Watson 888ed9f0ae Support keyword arguments for font attributes 2019-01-16 13:04:31 -05:00
Michael Krabbe Borregaard 57da253fa8 Merge pull request #1894 from sswatson/fontrotationfix
Fix annotation font rotation in PyPlot backend
2019-01-16 19:02:54 +01:00
Samuel S. Watson 44a6707397 Fix annotation font rotation 2019-01-16 10:28:46 -05:00
Samuel S. Watson f0a3ca4314 Merge remote-tracking branch 'upstream/master' 2019-01-16 09:44:03 -05:00
Michael Krabbe Borregaard 9bbd52dcc2 Merge pull request #1893 from JuliaPlots/doc_pr
rebased docpr from sswatson
2019-01-16 15:08:37 +01:00
Samuel S. Watson f50862ac51 Remove blank lines 2019-01-16 15:04:01 +01:00
Samuel S. Watson 017bed1a07 Remove xydoc and xyzdoc 2019-01-16 15:04:01 +01:00
Iblis Lin 3765d5f549 change contour example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-16 15:04:01 +01:00
Iblis Lin dd28159564 remove rand from example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-16 15:04:01 +01:00
Samuel S. Watson 63cdf9f8e7 Add shorthands.jl 2019-01-16 15:04:01 +01:00
Samuel S. Watson e30889aa12 document @shorthands functions 2019-01-16 15:04:01 +01:00
Samuel S. Watson b7caec1bfe Remove blank lines 2019-01-16 08:43:43 -05:00
Samuel S. Watson 660786b99c Merge branch 'master' of https://github.com/sswatson/Plots.jl 2019-01-16 08:41:02 -05:00
Samuel S. Watson b060576209 Remove xydoc and xyzdoc 2019-01-16 08:40:25 -05:00
Michael Krabbe Borregaard 7b3826c2d5 Merge pull request #1448 from OliverEvans96/gif_cache
Remove cache-busting from gif animation. Should be done by the frontend.
2019-01-16 09:30:39 +01:00
Michael Krabbe Borregaard 51d4416b00 Merge pull request #1891 from mkborregaard/master
filter infinite values in histograms too
2019-01-14 23:09:59 +01:00
Michael Krabbe Borregaard cfe6103f48 filter infinite values in histograms too 2019-01-14 23:08:50 +01:00
Michael Krabbe Borregaard bee8230079 Merge pull request #1889 from mkborregaard/master
fix histograms with NaN; close #1212
2019-01-14 11:45:04 +01:00
Michael Krabbe Borregaard 3d77c59c92 don't rebind vs 2019-01-14 11:44:42 +01:00
Michael Krabbe Borregaard 667ed161c0 move filtering to makebins 2019-01-14 10:36:08 +01:00
Michael Krabbe Borregaard 979f9495f1 add faster method for 1-d histogram 2019-01-14 00:04:01 +01:00
Michael Krabbe Borregaard d29a44efa7 fix histograms with NaN 2019-01-13 12:45:24 +01:00
Michael Krabbe Borregaard 7750003033 Merge pull request #1885 from sglyon/sl/plotlyjs-fix
Sl/plotlyjs fix
2019-01-11 19:52:02 +01:00
Iblis Lin e673339dc4 change contour example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-10 08:46:38 -05:00
Iblis Lin b20b47f8eb remove rand from example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-10 08:44:41 -05:00
Samuel S. Watson 689e437bac Add shorthands.jl 2019-01-08 18:10:48 -05:00
Samuel S. Watson e6bb17dc86 document @shorthands functions 2019-01-08 17:55:52 -05:00
Spencer Lyon 80a97b0f26 ENH: use PlotlyJS.savefig(::IO, ...) methods instead of former plotlyjs_save_hack hack 2019-01-08 14:04:33 -05:00
Spencer Lyon ffea050bc2 ENH: don't special case html display for jupyter 2019-01-08 14:04:03 -05:00
Josef Heinen 8951526d0d Set minimum GR version 2019-01-07 13:26:08 +01:00
Michael Krabbe Borregaard 3e799fbe21 Merge pull request #1880 from jheinen/master
Added support for discrete contour plots
2019-01-06 11:30:33 +01:00
Josef Heinen 53e27dbc38 Added support for discrete contour plots 2019-01-06 11:24:45 +01:00
Michael Krabbe Borregaard 9985d303ce Merge pull request #1879 from wfrgra/round_axis_limits
stop default axis widen behaviour overriding axis limit rounding
2019-01-06 08:11:43 +01:00
Michael Krabbe Borregaard ba46299088 Fix stray srand in showtheme 2019-01-05 17:59:18 +01:00
wfrgra 9679eae662 stop default widen behaviour overriding axis limit rounding 2019-01-05 13:46:53 +11:00
Michael Krabbe Borregaard 7acb5a4bdb allow annotations to take a tuple and pass it to text 2019-01-02 17:39:28 +01:00
Michael Krabbe Borregaard d1428b8221 update news.md 2018-12-29 10:05:02 +01:00
Michael Krabbe Borregaard c59a361ab3 Merge pull request #1875 from pfitzseb/sp/fixtypo
PlotDisplay -> PlotsDisplay
2018-12-29 09:46:54 +01:00
Sebastian Pfitzner 8935728daa PlotDisplay -> PlotsDisplay 2018-12-29 09:34:53 +01:00
Michael Krabbe Borregaard 155ac91385 Merge pull request #1874 from pfitzseb/sp/displayfixagain
insert PlotDisplay directly after REPLDisplay
2018-12-27 11:22:12 +01:00
Sebastian Pfitzner 4403ed3860 insert PlotDisplay directly after REPLDisplay 2018-12-27 10:57:10 +01:00
Michael Krabbe Borregaard 712b567752 update news for release 2018-12-10 11:02:34 +01:00
Michael Krabbe Borregaard 75be945359 Revert "MethodError -> ArgumentError"
This reverts commit 6f821e5344.
2018-12-07 09:42:44 +01:00
Michael Krabbe Borregaard fe50a457cd Merge pull request #1862 from mkborregaard/master
Fix MethodError to ArgumentError; fix #1861
2018-12-07 08:13:38 +01:00
Michael Krabbe Borregaard 6f821e5344 MethodError -> ArgumentError 2018-12-07 08:12:41 +01:00
Michael Krabbe Borregaard 14cbfb5706 fix warn -> @warn 2018-12-07 08:11:30 +01:00
Michael Krabbe Borregaard a882685169 Merge pull request #1857 from BoundaryValueProblems/master
vmin, vmax in KW were suppressed for :wireframe
2018-12-03 08:09:34 +01:00
Naoki Saito b9b7edc72d vmin, vmax in KW were suppressed for :wireframe 2018-12-02 15:37:25 -08:00
Michael Krabbe Borregaard d0b939da4a Merge pull request #1854 from mauro3/patch-1
Fix #1799
2018-11-28 17:22:55 +01:00
Mauro 2643d493a3 Fix #1799
This may fix #1799.  Although, note, I have no deeper understanding of this code...
2018-11-28 17:07:38 +01:00
Michael Krabbe Borregaard c26689fcb1 Merge pull request #1850 from greimel/gre/pgf-axes
Use :foreground_color_border for axis color in pgfplot
2018-11-19 22:37:48 +01:00
Fabian Greimel a2365f2c14 Use :foreground_color_border for axis color in pgfplot 2018-11-19 22:21:21 +01:00
Daniel Schwabeneder 435ff795ca Merge pull request #1841 from daschw/docs-formatter
add :plain formatter option in arg_desc (fix #1840)
2018-11-11 21:57:35 +01:00
Daniel Schwabeneder af34fdc45a add :plain formatter option in arg_desc 2018-11-11 21:25:41 +01:00
Michael Krabbe Borregaard 3bfedd844e Merge pull request #1838 from tkf/smuggle
Smuggle PyCall and LaTeXStrings through PyPlot
2018-11-09 08:20:55 +01:00
Takafumi Arakaki f726151e6e Smuggle PyCall and LaTeXStrings through PyPlot
fix #1672
fix https://github.com/JuliaPy/PyPlot.jl/issues/389
fix https://github.com/JuliaPy/PyPlot.jl/issues/408
2018-11-08 19:23:32 -08:00
Daniel Schwabeneder c6c4becf7d Merge pull request #1808 from JonathanAnderson/patch-1
Fallback to non gr3 surface call
2018-11-02 13:05:36 +01:00
Michael Krabbe Borregaard e2deb71988 Merge pull request #1828 from harryscholes/#1827
Fixes #1827
2018-10-31 14:00:09 +01:00
Harry a717bf4f34 Fixes #1827 2018-10-31 12:24:04 +00:00
Daniel Schwabeneder 2fef7a5b84 Merge pull request #1822 from JuliaPlots/revert-1821-revert-1819-mkb/plotrecipes
Revert "Revert "Transfer portfoliocomposition recipe from PlotRecipes""
2018-10-30 16:26:58 +01:00
Daniel Schwabeneder 12309c281b Revert "Revert "Transfer portfoliocomposition recipe from PlotRecipes"" 2018-10-30 16:26:19 +01:00
Daniel Schwabeneder a2a4e5b350 Merge pull request #1821 from JuliaPlots/revert-1819-mkb/plotrecipes
Revert "Transfer portfoliocomposition recipe from PlotRecipes"
2018-10-30 16:07:11 +01:00
Daniel Schwabeneder 6741287ef1 Revert "Transfer portfoliocomposition recipe from PlotRecipes" 2018-10-30 16:06:51 +01:00
Daniel Schwabeneder 6940f5a982 Merge pull request #1819 from JuliaPlots/mkb/plotrecipes
Transfer portfoliocomposition recipe from PlotRecipes
2018-10-30 15:51:46 +01:00
Michael Krabbe Borregaard b0bd5c13a0 Merge pull request #1820 from diegozea/patch-1
It solves Shape bugs
2018-10-30 15:17:11 +01:00
Diego Javier Zea af119a0248 It solves Shape bugs
unneeded get and missing undef
2018-10-30 15:15:03 +01:00
Michael Krabbe Borregaard 759cd7b3f2 add seed! 2018-10-30 14:05:31 +01:00
Michael Krabbe Borregaard 5e06e0d2d2 fix example 2018-10-30 14:05:31 +01:00
Michael Krabbe Borregaard 85b83e1745 add portfoliocomposition 2018-10-30 14:05:31 +01:00
Simon 441954be35 Merge pull request #1818 from JuliaPlots/mkb/dev2
Deprecate glivisualize backend - replaces #1816
2018-10-30 12:52:27 +01:00
Daniel Schwabeneder 11c1a23dfe Merge pull request #1815 from daschw/heatmap
allow heatmap of nx1 or 1xn matrices
2018-10-30 11:54:57 +01:00
Michael Krabbe Borregaard 1386435b17 Completely deprecate glvisualize 2018-10-30 11:41:37 +01:00
Michael Krabbe Borregaard f33d135182 More completely remove deprecated backends 2018-10-30 11:41:27 +01:00
Daniel Schwabeneder 5396477082 alow heatmap of nx1 or 1xn matrices 2018-10-30 09:02:58 +01:00
Jonathan Anderson 5ea77cc4b6 Fallback to non gr3 surface call
Taking an idea from @FlorianRhiem in this issue https://github.com/jheinen/GR.jl/issues/159, I figured I would fall back to GR if GR3 had an error. With this change, I was able to solve my issue in https://github.com/JuliaPlots/Plots.jl/issues/1781
2018-10-24 16:45:23 -05:00
Daniel Schwabeneder 45b5b33929 Merge pull request #1805 from yha/function-recipe-scale
function recipe: taking axis scales into account
2018-10-24 09:19:38 +02:00
Daniel Schwabeneder 9213b09c57 Merge pull request #1803 from daschw/staticarrays
remove FixedSizeArrays fix #1802
2018-10-23 19:45:30 +02:00
Daniel Schwabeneder 113e616d25 remove FixedSizeArrays 2018-10-23 17:53:25 +02:00
Daniel Schwabeneder 8861c553da Merge pull request #1801 from PhilipVinc/philipvinc-labels_mirror_fix
Fix Mirroring of Labels
2018-10-23 17:35:02 +02:00
Filippo Vicentini 6be7995500 Add paddings to the side where the axis label is 2018-10-23 15:58:10 +02:00
Filippo Vicentini 89d08606ad Mirror guides if :guide_position == :auto and :mirror == true
Before, guides where mirrored only if guide_position was set.
2018-10-23 14:05:05 +02:00
Michael Krabbe Borregaard e709560319 Merge pull request #1800 from jheinen/master
up GR version
2018-10-23 10:00:35 +02:00
Josef Heinen 9eda7548d0 Merge remote-tracking branch 'upstream/master'
t push
2018-10-23 08:51:04 +02:00
Josef Heinen 6e0522308a up GR version 2018-10-23 08:50:25 +02:00
Josef Heinen 7062e8864b up GR version 2018-10-23 08:46:07 +02:00
yharel 957cea2638 function recipe: taking axis scales into account 2018-10-22 03:11:26 +03:00
Daniel Schwabeneder 532710e6bf Merge pull request #1791 from daschw/release
prepare release
2018-10-14 19:12:42 +02:00
Daniel Schwabeneder 24e46e4c01 Merge pull request #1790 from daschw/appveyor
don't test for julia 0.7 on appveyor
2018-10-14 19:11:52 +02:00
Daniel Schwabeneder cb3cdbf6e7 prepare release 2018-10-14 19:10:12 +02:00
Daniel Schwabeneder dcceef2e52 Merge pull request #1782 from ma-laforge/hdf5
Add support for annotations and "Shape"s.
2018-10-14 18:40:44 +02:00
Daniel Schwabeneder cbc965dc53 Merge pull request #1787 from greimel/gre/gr-axis-color
GR: use correct attribute for axis color
2018-10-14 18:39:39 +02:00
Daniel Schwabeneder f5b793f80c Merge pull request #1777 from JuliaPlots/sd-remote
use remote urls plotly
2018-10-14 18:36:10 +02:00
Daniel Schwabeneder d3b51703f2 don't test for julia 0.7 on appveyor 2018-10-14 18:27:36 +02:00
Daniel Schwabeneder 0ecee70af2 Merge branch 'master' into sd-remote 2018-10-14 18:11:21 +02:00
Daniel Schwabeneder 061704ac6e Merge pull request #1789 from daschw/docs2
Prepare for PlotDocs.
2018-10-14 16:12:46 +02:00
Daniel Schwabeneder 3e1ce8c2fa really fix conflicts 2018-10-14 15:51:02 +02:00
Daniel Schwabeneder 1cc84672e7 fix conflicts 2018-10-14 15:50:10 +02:00
Daniel Schwabeneder 04f502df8a select pgfplots examples for docs 2018-10-14 15:38:50 +02:00
Daniel Schwabeneder 22c3afd8a0 remove is_installed 2018-10-14 14:11:16 +02:00
Daniel Schwabeneder d9be97fc45 fix pgfplots saving with FileIO 2018-10-14 14:09:43 +02:00
Fabian Greimel b04e6ff699 GR: use correct attribute for axis color 2018-10-13 14:07:19 +02:00
Daniel Schwabeneder 9c1a5548e1 small PGFPlots fix in backends.jl 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder b73d7f03a7 don't add PyPlot and PlotlyJS in tests 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 106ed6b953 one more fix for plotlyjs 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder cccbaa0bdc skip visual regression tests on windows 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 874dacd2c8 fix plotlyjs (fix #1728) 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder a72a23b548 move supported backend attr to backends.jl 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 31004e8c12 move _current_plots_version from PlotDocs to Plots 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 87c471c0f5 plotlyjs, pyplot and test fixes 2018-10-09 20:56:02 +02:00
Michael Krabbe Borregaard d3e1a423fd update news for release 2018-10-08 16:17:01 +02:00
MA Laforge 16cc743d26 Add support for annotations and "Shape"s.
Also build plot attributes list after series are read in
to avoid having the internal mechanisms overwrite data.
2018-10-08 06:54:01 -07:00
SimonDanisch 9ccb699fca improve comments 2018-10-05 12:33:13 +02:00
SimonDanisch 7e0960e7a0 fix IJulia 2018-10-05 12:27:09 +02:00
SimonDanisch ee4fc2803b dont download by default 2018-10-05 12:27:01 +02:00
djsegal 268c2861c9 Fix off-by-one error in pyplot scatter building 2018-10-04 17:29:37 -04:00
djsegal 15739bc0ee Allow vectors of markers for pyplot scatter 2018-10-04 17:20:14 -04:00
Michael Krabbe Borregaard e84de56f2e Merge pull request #1779 from JackDunnNZ/patch-1
Minor formatting fix
2018-10-04 16:42:35 +02:00
Jack Dunn 6b46e81fbd Update backends.jl 2018-10-04 09:50:43 -04:00
SimonDanisch f5de5f58ce make ijulia plotly integration precompile save 2018-10-04 15:39:59 +02:00
SimonDanisch 3c2cfa333c allow to not host plotly from local file 2018-10-04 15:20:21 +02:00
Daniel Schwabeneder 63bc3a2b88 Merge pull request #1772 from daschw/incremental-compilation
Fix incremental compilation warnings (fix #1692, fix #1734)
2018-09-30 20:20:14 +02:00
Daniel Schwabeneder 1e83bc05ee move including of default backends out of __init__() 2018-09-30 18:03:22 +02:00
Michael Krabbe Borregaard acb9faa6e3 Merge pull request #1765 from pfitzseb/sp/juno2
honour `html_output_format` in Juno
2018-09-27 21:12:19 +02:00
Daniel Schwabeneder 732103abf7 Merge pull request #1766 from daschw/release
prepare release
2018-09-27 09:25:04 +02:00
Daniel Schwabeneder 90223ff514 prepare release 2018-09-27 09:23:56 +02:00
Sebastian Pfitzner ec8084823c slightly nicer method error 2018-09-26 17:45:51 +02:00
Sebastian Pfitzner 05b55fa8dc honour html_output_format in Juno 2018-09-26 17:40:09 +02:00
Daniel Schwabeneder eaad735d22 Merge pull request #1743 from Godisemo/pgfplots-1.0
Fix Julia v1.0 deprecations for pgfplots backend
2018-09-14 19:11:23 +02:00
Godisemo ecf483702f Fix deprecated syntax in PGFPlots backend 2018-09-14 10:36:49 +02:00
Godisemo 2e9e1fc424 Fix Julia v1.0 deprecations for pgfplots backend 2018-09-14 10:02:15 +02:00
Michael Krabbe Borregaard b5c73d1574 Merge pull request #1741 from Godisemo/pyplot-feature-pr
Add option to change guide positions
2018-09-14 09:31:43 +02:00
Godisemo beb73d891d Document new guide_position argument 2018-09-14 09:19:56 +02:00
Godisemo a4edd8e41f Add option to change guide positions in pgfplots 2018-09-13 18:32:30 +02:00
Godisemo cac3dae96c Add option to change guide positions in gr 2018-09-13 12:01:12 +02:00
Godisemo 279ef2075f Add option to change guide positions in pyplot 2018-09-13 11:22:49 +02:00
Daniel Schwabeneder 5d0740c0e5 Merge pull request #1737 from ma-laforge/inspectdr
Re-establish support for alpha on markers (InspectDR).
2018-09-12 09:42:25 +02:00
MA Laforge 9ee8055093 Activate :seriescolor, :seriesalpha attributes. 2018-09-11 18:04:03 -07:00
MA Laforge 07ed7eb6dd Re-establish alpha support on lines, etc (InspectDR). 2018-09-10 20:47:27 -07:00
MA Laforge ed6878a48f Re-establish support for alpha on markers (InspectDR). 2018-09-10 19:57:29 -07:00
Michael Krabbe Borregaard 09a17ba783 up GR version 2018-09-07 22:40:56 +02:00
Michael Krabbe Borregaard 046b291c1f remove the then 2018-09-07 16:02:19 +02:00
Michael Krabbe Borregaard 187a19bfd1 Merge pull request #1731 from mkborregaard/missings
rudimentary missings support
2018-09-07 15:54:22 +02:00
Michael Krabbe Borregaard 91816e6715 rename handlemissingsinmatrix 2018-09-07 15:38:20 +02:00
Michael Krabbe Borregaard 13339125eb drop stray @show 2018-09-07 15:31:04 +02:00
Michael Krabbe Borregaard 3197db9fc1 Merge pull request #1726 from mkborregaard/master
Run Travis on 1.0
2018-09-07 15:26:40 +02:00
Michael Krabbe Borregaard 6e4aac1123 Run Travis on 1.0 2018-09-07 15:26:06 +02:00
Michael Krabbe Borregaard 94450a26e9 restore String 2018-09-07 15:16:10 +02:00
Michael Krabbe Borregaard f571596eda Matrix support 2018-09-07 15:04:53 +02:00
Michael Krabbe Borregaard 8b6ca96e0a rudimentary missings support 2018-09-07 14:42:14 +02:00
Michael Krabbe Borregaard 198de2607a Merge pull request #1703 from daschw/appveyor
try default appveyor.yml
2018-09-07 09:59:09 +02:00
Josef Heinen 7cd1c9e8c8 Merge pull request #1729 from jheinen/master
gr: use new DPI setting for SVG output
2018-09-07 09:58:52 +02:00
Daniel Schwabeneder fc51c355a5 don't add PyPlot and PlotlyJS in tests 2018-09-06 22:53:32 +02:00
Daniel Schwabeneder 59e7213c96 one more fix for plotlyjs 2018-09-06 22:30:42 +02:00
Daniel Schwabeneder 192020a93a skip visual regression tests on windows 2018-09-06 22:08:32 +02:00
Daniel Schwabeneder 5f5019d310 fix plotlyjs (fix #1728) 2018-09-06 22:04:44 +02:00
Josef Heinen 9aa201dcb3 gr: use new DPI setting for SVG output 2018-09-06 21:37:18 +02:00
Daniel Schwabeneder f0f90d87af move supported backend attr to backends.jl 2018-09-04 19:08:48 +02:00
Daniel Schwabeneder 1bbe800dcd move _current_plots_version from PlotDocs to Plots 2018-09-03 17:30:50 +02:00
Daniel Schwabeneder a731ef6e2d plotlyjs, pyplot and test fixes 2018-09-02 22:28:34 +02:00
Josef Heinen 25b09a7962 Merge remote-tracking branch 'upstream/master'
t push
2018-08-30 10:19:25 +02:00
Michael Krabbe Borregaard 80151ac1a3 Merge pull request #1711 from mkborregaard/master
fix plotly errors; fix #1707
2018-08-29 18:49:27 +02:00
Michael Krabbe Borregaard bad5668ff7 Merge pull request #1704 from mkborregaard/old_spy
Reinstate scatter-based spy implementation; fix #1682
2018-08-29 18:41:20 +02:00
Michael Krabbe Borregaard cad0f15aed fix plotly errors 2018-08-29 18:38:53 +02:00
Josef Heinen 2405d5151b Merge remote-tracking branch 'upstream/master'
t push
2018-08-29 07:42:46 +02:00
Michael Krabbe Borregaard 9887892a92 reinstate marker_z 2018-08-28 09:55:15 +02:00
Daniel Schwabeneder 6fa15751ae try default appveyor.yml 2018-08-27 19:38:57 +02:00
Josef Heinen 24e3fcbb6c Merge remote-tracking branch 'upstream/master'
t push
2018-08-27 08:33:21 +02:00
Michael Krabbe Borregaard 91f51778f1 Don't define invisible when two colors 2018-08-26 23:10:33 +02:00
Michael Krabbe Borregaard 5c2bf5d76c Don't color points 2018-08-26 23:10:33 +02:00
Michael Krabbe Borregaard c4233e2896 larger markers 2018-08-26 23:10:33 +02:00
Michael Krabbe Borregaard e0b7bdc1a5 Revert "Merge pull request #1155 from mkborregaard/newspy"
This reverts commit b71cfce105.
2018-08-26 23:10:33 +02:00
Josef Heinen ae969dad38 Merge remote-tracking branch 'upstream/master'
t push
2018-08-24 04:18:05 -04:00
Josef Heinen 065ff48b15 Merge remote-tracking branch 'upstream/master'
t push
2018-08-22 06:12:20 -04:00
Josef Heinen 1e9467a221 Merge remote-tracking branch 'upstream/master'
t push
2018-08-16 10:48:48 +02:00
Josef Heinen 916654b3ec Merge remote-tracking branch 'upstream/master'
t push
2018-08-15 07:51:30 +02:00
Josef Heinen ad1bcbb0ac Merge remote-tracking branch 'upstream/master'
t push
2018-08-14 10:13:06 +02:00
Josef Heinen c0ff8f80b1 t push
Merge remote-tracking branch 'upstream/master'
2018-08-13 11:41:59 +02:00
Josef Heinen 5485740291 Merge remote-tracking branch 'upstream/master'
t push
2018-08-12 19:38:17 +02:00
Josef Heinen 5565680b53 t push
Merge remote-tracking branch 'upstream/master'
2018-08-10 19:57:25 +01:00
Josef Heinen 15ddc5f06c Merge remote-tracking branch 'upstream/master' 2018-08-01 13:18:22 +02:00
Josef Heinen 3559b539e3 gr: use correct text bounding box for mathtex 2018-07-31 16:06:37 +02:00
Daniel Schwabeneder c2e8b5a1fa Merge pull request #1611 from daschw/pyplot-thickness
Fix pyplot thickness and 0.6 backports release
2018-07-26 17:03:48 +02:00
Oliver Evans 1a67ca897c Remove cache-busting from gif animation. Should be done by the frontend. 2018-03-21 12:25:06 -04:00
Michael Krabbe Borregaard d1980ef978 Merge pull request #775 from JonathanAnderson/julia0.6
Update gr.jl in v0.6 so inline plots work
2017-05-08 10:07:40 +02:00
Jonathan Anderson b3db49b4ae Update gr.jl in v0.6 so inline plots work
I wanted to switch from using GR directly to using Plots, but the inline plots were not working for me. The following change is sufficient to generate inline plots in iterm for me.

See the method in GR.jl:
https://github.com/jheinen/GR.jl/blob/0f167b2be921a0014c405f760a1e1bc22b222751/src/GR.jl#L3014

julia> versioninfo()
Julia Version 0.6.0-pre.beta.187
Commit 55c97fb* (2017-04-17 23:06 UTC)
Platform Info:
OS: Linux (x86_64-redhat-linux)
CPU: Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.9.1 (ORCJIT, haswell)


julia> using TerminalExtensions
julia> using Plots
julia> gr(display_type=:inline);
julia> z=[sin(sqrt(x^2+y^2)) for x in linspace(-2π,2π,50), y in linspace(-2π,2π,50)];
julia> contour(z)
2017-04-18 10:39:50 -05:00
53 changed files with 2721 additions and 6779 deletions
+2
View File
@@ -6,3 +6,5 @@ examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js
deps/build.log
deps/deps.jl
Manifest.toml
+5 -45
View File
@@ -4,57 +4,17 @@ os:
- linux
# - osx
julia:
# - 0.7
- 1.1
- nightly
# matrix:
# allow_failures:
# - julia: nightly
# # before install:
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install wkhtmltopdf; fi
# ref: http://askubuntu.com/a/556672 for the wkhtmltopdf apt repository info
matrix:
allow_failures:
- julia: nightly
sudo: required
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test/install_wkhtmltoimage.sh ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:pov/wkhtmltopdf ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y wkhtmltopdf ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltopdf -V ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltoimage -V ; fi
# echo 'exec xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@"' | sudo tee /usr/local/bin/wkhtmltopdf.sh >/dev/null
# sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh
# # borrowed from Blink.jl's travis file
# matrix:
# include:
# - os: linux
# julia: 0.4
# env: TESTCMD="xvfb-run julia"
# - os: osx
# julia: 0.4
# env: TESTCMD="julia"
notifications:
email: true
# uncomment the following lines to override the default test script
# script:
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
# - julia -e 'import Pkg; Pkg.add(Pkg.PackageSpec(path=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")'
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
# # - julia -e 'Pkg.clone("https://github.com/JunoLab/Blink.jl.git"); Pkg.build("Blink"); import Blink; Blink.AtomShell.install()'
# # - julia -e 'Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")'
# - julia -e 'ENV["PYTHON"] = ""; Pkg.add("PyPlot"); Pkg.build("PyPlot")'
#
# # - $TESTCMD -e 'Pkg.test("Plots"; coverage=false)'
# - julia -e 'Pkg.test("Plots"; coverage=false)'
# # - julia -e 'cd(Pkg.dir("Plots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
+95 -5
View File
@@ -10,7 +10,97 @@
---
## (current master)
- All new development should target Julia 1.x!
## 0.25.1
- fix gr_display
## 0.25.0
- Replace StaticArrays with GeometryTypes
- Contour fixes for GR
## 0.24.0
- Update to the new PyCall and PyPlot API
- fix drawing of ticks
- fix y label position with GR
## 0.23.2
- pyplot fixes
- Add option :tex_output_standalone to set the 'include_preamble' argument in the PGFPlots backend.
- fix ticks
- support plotly json mime
- fix image axis limits
- default to radius 0 at center for polar plots
## 0.23.1
- slightly faster load time
- fixed errant MethodError
- fix bar plots with unicodeplots
- better colorbars for contour
- add volume seriestype for GR
- fix passing a tuple to custom ticks
- add vline to pgfplots
- add tex output for pyplot
- better 3d axis labels for GR
## 0.23.0
- compatible with StatPlots -> StatsPlots name shift
- fix histograms for vectors with NaN and Inf
- change gif behaviour (remove cache-busting)
- improved docstrings for shorthands functions
- fix font rotation for pyplot
- fix greyscale images for pyplot
- clamp greyscale images with values outside 0,1
- support keyword argument for font options
- allow vector of markers for pyplot scatter
## 0.22.5
- improve behaviour of plotlyjs backend
## 0.22.4
- Add support for discrete contourf plots with GR
## 0.22.3
- Fix the `showtheme` function
## 0.22.2
- Allow annotations to accept a Tuple instead of the result of a text call (making it possible to specify font characteristics in recipes). E.g. `annotations = (2, 4, ("test", :right, 8, :red))` is the same as `annotations = (2, 4, text("test", :right, 8, :red))`
## 0.22.1
- push PlotsDisplay just after REPLDisplay
## 0.22.0
- deprecate GLVisualize
- allow 1-row and 1-column heatmaps
- add portfoliodecomposition recipe from PlotRecipes
- solve Shape bug
- simplify PyPlot backend installation
- fix wireframe bug in PyPlot
- fix color bug in PyPlot
- minor bug fixes in gr and pyplot
## 0.21.0
- Compatibility with StaticArrays 0.9.0
- Up GR min version to 0.35
- fix :mirror
## 0.20.6
- fixes for PlotDocs.jl
- fix gr axis color argument
- Shapes for inspectdr
- don't load plotly js file by default
## 0.20.5
- fix precompilation issue when depending on Plots
## 0.20.4
- honour `html_output_format` in Juno
## 0.20.3
- implement guide position in gr, pyplot and pgfplots
- inspectdr fixes
- default appveyor
- rudimentary missings support
- deprecation fixes for PGFPlots
## 0.20.0
Many updates, min julia 1.0
@@ -146,7 +236,7 @@ Many updates, min julia 1.0
- add `reset_defaults()` function to reset plot defaults
- update syntax to 0.6
- make `fill = true` fill to 0 rather than to 1
- use new `@df` syntax in StatPlots examples
- use new `@df` syntax in StatsPlots examples
- allow changing the color of legend box
- implement `title_location` for gr
- add `hline` marker to pgfplots - fixes errorbars
@@ -298,7 +388,7 @@ Many updates, min julia 1.0
- added dependency on PlotThemes
- set_theme --> theme
- remove Compat from REQUIRE
- warning for DataFrames without StatPlots
- warning for DataFrames without StatsPlots
- closeall exported and implemented for gr/pyplot
- fix DateTime recipe
- reset theme with theme(:none)
@@ -420,8 +510,8 @@ Many updates, min julia 1.0
#### 0.8.0
- added dependency on PlotUtils
- BREAKING: removed DataFrames support (now in StatPlots.jl)
- BREAKING: removed boxplot/violin/density recipes (now in StatPlots.jl)
- BREAKING: removed DataFrames support (now in StatsPlots.jl)
- BREAKING: removed boxplot/violin/density recipes (now in StatsPlots.jl)
- GR:
- inline iterm2 support
- trisurface support
+56
View File
@@ -0,0 +1,56 @@
name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"]
version = "0.25.3"
[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[compat]
FixedPointNumbers = "≥ 0.3.0"
GR = "≥ 0.31.0"
PlotThemes = "≥ 0.1.3"
PlotUtils = "≥ 0.4.1"
RecipesBase = "≥ 0.6.0"
StatsBase = "≥ 0.14.0"
julia = "≥ 1.0.0"
[extras]
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
BinaryProvider = "b99e7846-7c00-51b0-8f62-c81ae34c0232"
[targets]
test = ["BinaryProvider", "Pkg", "Test", "Random", "StatsPlots", "VisualRegressionTests", "LaTeXStrings", "Images", "ImageMagick", "RDatasets", "FileIO", "UnicodePlots"]
-16
View File
@@ -1,16 +0,0 @@
julia 1.0
RecipesBase 0.6.0
PlotUtils 0.4.1
PlotThemes 0.1.3
Reexport
StaticArrays 0.5
FixedPointNumbers 0.3
Measures
Showoff
StatsBase 0.14.0
JSON
NaNMath
Requires
Contour
GR 0.31.0
+28 -26
View File
@@ -1,14 +1,23 @@
environment:
matrix:
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
# - julia_version: 0.7
- julia_version: 1
- julia_version: nightly
# matrix:
# allow_failures:
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
platform:
- x86 # 32-bit
- x64 # 64-bit
# # Uncomment the following lines to allow failures on nightly julia
# # (tests will run but not make your overall status red)
matrix:
allow_failures:
- julia_version: nightly
branches:
only:
- master
- /release-.*/
notifications:
- provider: Email
@@ -17,25 +26,18 @@ notifications:
on_build_status_changed: false
install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# If there's a newer build queued for the same PR, cancel this one
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." }
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile($env:JULIA_URL, "C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
- ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))
build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "
using InteractiveUtils, Pkg;
versioninfo();
Pkg.clone(pwd(), \"Plots\");
Pkg.build(\"Plots\")"
- echo "%JL_BUILD_SCRIPT%"
- C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"
test_script:
- C:\projects\julia\bin\julia -e "using Pkg; Pkg.test(\"Plots\")"
- echo "%JL_TEST_SCRIPT%"
- C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"
# # Uncomment to support code coverage upload. Should only be enabled for packages
# # which would have coverage gaps without running on Windows
# on_success:
# - echo "%JL_CODECOV_SCRIPT%"
# - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%"
+15 -5
View File
@@ -1,8 +1,18 @@
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
file_path = ""
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global file_path
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
isfile(local_fn) && (file_path = local_fn)
else
file_path = local_fn
end
end
open("deps.jl", "w") do io
println(io, "const plotly_local_file_path = $(repr(file_path))")
end
+21 -94
View File
@@ -1,10 +1,11 @@
module Plots
_current_plots_version = v"0.25.0"
using Reexport
import StaticArrays
using StaticArrays.FixedSizeArrays
using Dates, Printf, Statistics, Base64, LinearAlgebra
import GeometryTypes
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
import SparseArrays: findnz
@reexport using RecipesBase
@@ -18,6 +19,17 @@ import JSON
using Requires
if isfile(joinpath(@__DIR__, "..", "deps", "deps.jl"))
include(joinpath(@__DIR__, "..", "deps", "deps.jl"))
else
# This is a bit dirty, but I don't really see why anyone should be forced
# to build Plots, while it will just include exactly the below line
# as long as `ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] = "true"` is not set.
# If the above env is set + `plotly_local_file_path == ""``,
# it will warn in the __init__ function to run build
const plotly_local_file_path = ""
end
export
grid,
bbox,
@@ -72,7 +84,6 @@ export
backends,
backend_name,
backend_object,
add_backend,
aliases,
Shape,
@@ -168,99 +179,15 @@ include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
include("output.jl")
include("ijulia.jl")
include("fileio.jl")
include("init.jl")
# ---------------------------------------------------------
include("backends/plotly.jl")
include("backends/gr.jl")
include("backends/web.jl")
@shorthands scatter
@shorthands bar
@shorthands barh
@shorthands histogram
@shorthands barhist
@shorthands stephist
@shorthands scatterhist
@shorthands histogram2d
@shorthands density
@shorthands heatmap
@shorthands plots_heatmap
@shorthands hexbin
@shorthands sticks
@shorthands hline
@shorthands vline
@shorthands hspan
@shorthands vspan
@shorthands ohlc
@shorthands contour
@shorthands contourf
@shorthands contour3d
@shorthands surface
@shorthands wireframe
@shorthands path3d
@shorthands scatter3d
@shorthands boxplot
@shorthands violin
@shorthands quiver
@shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
include("shorthands.jl")
let PlotOrSubplot = Union{Plot, Subplot}
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
+12 -3
View File
@@ -93,16 +93,25 @@ end
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
# write out html to view the gif
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
ext = file_extension(agif.filename)
write(io, if ext == "gif"
"<img src=\"$(relpath(agif.filename))?$(rand())>\" />"
"<img src=\"$(relpath(agif.filename))\" />"
elseif ext in ("mov", "mp4")
"<video controls><source src=\"$(relpath(agif.filename))?$(rand())>\" type=\"video/$ext\"></video>"
"<video controls><source src=\"$(relpath(agif.filename)) type=\"video/$ext\"></video>"
else
error("Cannot show animation with extension $ext: $agif")
end)
return nothing
end
# Only gifs can be shown via image/gif
Base.showable(::MIME"image/gif", agif::AnimatedGif) = file_extension(agif.filename) == "gif"
function Base.show(io::IO, ::MIME"image/gif", agif::AnimatedGif)
open(fio-> write(io, fio), agif.filename)
end
+29 -25
View File
@@ -2,7 +2,7 @@
const _arg_desc = KW(
# series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
@@ -10,7 +10,7 @@ const _arg_desc = KW(
:linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area from this to y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
@@ -21,7 +21,7 @@ const _arg_desc = KW(
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(min(x), stop = extrema(x), length = 25)`",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
@@ -29,13 +29,13 @@ const _arg_desc = KW(
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
@@ -43,13 +43,14 @@ const _arg_desc = KW(
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:contour_labels => "Bool. Show labels at the contour lines?",
:contour_labels => "Bool. Show labels at the contour lines?",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
# plot args
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
:background_color => "Color Type. Base color for all backgrounds.",
@@ -63,11 +64,12 @@ const _arg_desc = KW(
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
: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",
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.",
: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.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
# subplot args
@@ -98,7 +100,7 @@ const _arg_desc = KW(
:legendfont => "Font. Font of legend items.",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units.",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
@@ -110,13 +112,14 @@ const _arg_desc = KW(
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args
:guide => "String. Axis guide (label).",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
:guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
@@ -148,4 +151,5 @@ const _arg_desc = KW(
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
)
+27 -17
View File
@@ -232,6 +232,7 @@ const _bar_width = 0.8
const _series_defaults = KW(
:label => "AUTO",
:colorbar_entry => true,
:seriescolor => :auto,
:seriesalpha => nothing,
:seriestype => :path,
@@ -298,6 +299,7 @@ const _plot_defaults = KW(
:link => :none,
:overwrite_figure => true,
:html_output_format => :auto,
:tex_output_standalone => false,
: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
@@ -350,6 +352,7 @@ const _subplot_defaults = KW(
const _axis_defaults = KW(
:guide => "",
:guide_position => :auto,
:lims => :auto,
:ticks => :auto,
:scale => :identity,
@@ -389,6 +392,7 @@ const _axis_defaults = KW(
:minorgrid => false,
:showaxis => true,
:widen => true,
:draw_arrow => false,
)
const _suppress_warnings = Set{Symbol}([
@@ -734,6 +738,10 @@ function processMarkerArg(plotattributes::KW, arg)
elseif allAlphas(arg)
plotattributes[:markeralpha] = arg
# bool
elseif typeof(arg) <: Bool
plotattributes[:markershape] = arg ? :circle : :none
# markersize
elseif allReals(arg)
plotattributes[:markersize] = arg
@@ -1022,7 +1030,7 @@ function preprocessArgs!(plotattributes::KW)
arrow()
elseif a in (false, nothing, :none)
nothing
elseif !(typeof(a) <: Arrow)
elseif !(typeof(a) <: Arrow || typeof(a) <: AbstractArray{Arrow})
arrow(wraptuple(a)...)
else
a
@@ -1049,8 +1057,8 @@ function preprocessArgs!(plotattributes::KW)
# warnings for moved recipes
st = get(plotattributes, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
@warn("seriestype $st has been moved to StatPlots. To use: \`Pkg.add(\"StatPlots\"); using StatPlots\`")
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots)
@warn("seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`")
end
return
@@ -1179,7 +1187,7 @@ function convertLegendValue(val::Symbol)
:best
elseif val in (:no, :none)
:none
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright)
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright, :outertopleft, :outertop, :outerright, :outerleft, :outerbottomright, :outerbottomleft, :outerbottom)
val
else
error("Invalid symbol for legend: $val")
@@ -1507,19 +1515,19 @@ function has_black_border_for_default(st::Symbol)
like_histogram(st) || st in (:hexbin, :bar, :shape)
end
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, sp::Subplot, n::Int)
# converts a symbol or string into a Colorant or ColorGradient
# and assigns a color automatically
function get_series_color(c, sp::Subplot, n::Int, seriestype)
if c == :auto
c = autopick(sp[:color_palette], n)
c = like_surface(seriestype) ? cgrad() : autopick(sp[:color_palette], n)
elseif isa(c, Int)
c = autopick(sp[:color_palette], c)
end
plot_color(c)
end
function getSeriesRGBColor(c::AbstractArray, sp::Subplot, n::Int)
map(x->getSeriesRGBColor(x, sp, n), c)
function get_series_color(c::AbstractArray, sp::Subplot, n::Int, seriestype)
map(x->get_series_color(x, sp, n, seriestype), c)
end
function ensure_gradient!(plotattributes::KW, csym::Symbol, asym::Symbol)
@@ -1564,21 +1572,23 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot)
end
# update series color
plotattributes[:seriescolor] = getSeriesRGBColor(plotattributes[:seriescolor], sp, plotIndex)
scolor = plotattributes[:seriescolor]
stype = plotattributes[:seriestype]
plotattributes[:seriescolor] = scolor = get_series_color(scolor, sp, plotIndex, stype)
# update other colors
for s in (:line, :marker, :fill)
csym, asym = Symbol(s,:color), Symbol(s,:alpha)
plotattributes[csym] = if plotattributes[csym] == :auto
plot_color(if has_black_border_for_default(plotattributes[:seriestype]) && s == :line
plot_color(if has_black_border_for_default(stype) && s == :line
sp[:foreground_color_subplot]
else
plotattributes[:seriescolor]
scolor
end)
elseif plotattributes[csym] == :match
plot_color(plotattributes[:seriescolor])
plot_color(scolor)
else
getSeriesRGBColor(plotattributes[csym], sp, plotIndex)
get_series_color(plotattributes[csym], sp, plotIndex, stype)
end
end
@@ -1586,9 +1596,9 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot)
plotattributes[:markerstrokecolor] = if plotattributes[:markerstrokecolor] == :match
plot_color(sp[:foreground_color_subplot])
elseif plotattributes[:markerstrokecolor] == :auto
getSeriesRGBColor(plotattributes[:markercolor], sp, plotIndex)
get_series_color(plotattributes[:markercolor], sp, plotIndex, stype)
else
getSeriesRGBColor(plotattributes[:markerstrokecolor], sp, plotIndex)
get_series_color(plotattributes[:markerstrokecolor], sp, plotIndex, stype)
end
# if marker_z, fill_z or line_z are set, ensure we have a gradient
+56 -28
View File
@@ -117,7 +117,7 @@ end
# -------------------------------------------------------------------------
Base.show(io::IO, axis::Axis) = dumpdict(axis.plotattributes, "Axis", true)
Base.show(io::IO, axis::Axis) = dumpdict(io, axis.plotattributes, "Axis", true)
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.plotattributes, k)
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v, ks...)
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k)
@@ -152,8 +152,8 @@ scalefunc(scale::Symbol) = x -> get(_scale_funcs, scale, identity)(Float64(x))
invscalefunc(scale::Symbol) = x -> get(_inv_scale_funcs, scale, identity)(Float64(x))
labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string)
function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
amin,amax = axis_limits(axis)
function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
amin, amax = axis_limits(sp, axis[:letter])
# scale the limits
scale = axis[:scale]
@@ -238,9 +238,9 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
end
# return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(axis::Axis)
function get_ticks(sp::Subplot, axis::Axis)
ticks = _transform_ticks(axis[:ticks])
ticks in (nothing, false) && return nothing
ticks in (:none, nothing, false) && return nothing
# treat :native ticks as :auto
ticks = ticks == :native ? :auto : ticks
@@ -251,7 +251,7 @@ function get_ticks(axis::Axis)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in range(1, stop=n, length=15)]
Int[round(Int,i) for i in range(1, stop=n, length=min(n,15))]
else # if ticks == :all
1:n
end
@@ -261,7 +261,7 @@ function get_ticks(axis::Axis)
(collect(0:pi/4:7pi/4), string.(0:45:315))
else
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
optimal_ticks_and_labels(sp, axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
if !isempty(dvals) && typeof(ticks) <: Int
@@ -269,7 +269,7 @@ function get_ticks(axis::Axis)
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
optimal_ticks_and_labels(sp, axis, ticks)
end
elseif typeof(ticks) <: NTuple{2, Any}
# assuming we're passed (ticks, labels)
@@ -286,12 +286,12 @@ _transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
function get_minor_ticks(axis,ticks)
axis[:minorticks] in (nothing, false) && !axis[:minorgrid] && return nothing
function get_minor_ticks(sp, axis, ticks)
axis[:minorticks] in (:none, nothing, false) && !axis[:minorgrid] && return nothing
ticks = ticks[1]
length(ticks) < 2 && return nothing
amin, amax = axis_limits(axis)
amin, amax = axis_limits(sp, axis[:letter])
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
if length(ticks) > 2
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
@@ -459,7 +459,7 @@ const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter
function default_should_widen(axis::Axis)
should_widen = false
if !is_2tuple(axis[:lims])
if !(is_2tuple(axis[:lims]) || axis[:lims] == :round)
for sp in axis.sps
for series in series_list(sp)
if series.plotattributes[:seriestype] in _widen_seriestypes
@@ -479,11 +479,13 @@ function round_limits(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))
function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(letter, :axis)]), consider_aspect = true)
axis = sp[Symbol(letter, :axis)]
ex = axis[:extrema]
amin, amax = ex.emin, ex.emax
lims = axis[:lims]
if (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
has_user_lims = (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
if has_user_lims
if isfinite(lims[1])
amin = lims[1]
end
@@ -497,12 +499,12 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
if !isfinite(amin) && !isfinite(amax)
amin, amax = 0.0, 1.0
end
if ispolar(axis.sps[1])
amin, amax = if ispolar(axis.sps[1])
if axis[:letter] == :x
amin, amax = 0, 2pi
elseif lims == :auto
#widen max radius so ticks dont overlap with theta axis
amin, amax + 0.1 * abs(amax - amin)
0, amax + 0.1 * abs(amax - amin)
else
amin, amax
end
@@ -513,6 +515,32 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
else
amin, amax
end
if !has_user_lims && consider_aspect && letter in (:x, :y) && !(sp[:aspect_ratio] in (:none, :auto) || is3d(:sp))
aspect_ratio = isa(sp[:aspect_ratio], Number) ? sp[:aspect_ratio] : 1
plot_ratio = height(plotarea(sp)) / width(plotarea(sp))
dist = amax - amin
if letter == :x
yamin, yamax = axis_limits(sp, :y, default_should_widen(sp[:yaxis]), false)
ydist = yamax - yamin
axis_ratio = aspect_ratio * ydist / dist
factor = axis_ratio / plot_ratio
else
xamin, xamax = axis_limits(sp, :x, default_should_widen(sp[:xaxis]), false)
xdist = xamax - xamin
axis_ratio = aspect_ratio * dist / xdist
factor = plot_ratio / axis_ratio
end
if factor > 1
center = (amin + amax) / 2
amin = center + factor * (amin - center)
amax = center + factor * (amax - center)
end
end
return amin, amax
end
# -------------------------------------------------------------------------
@@ -586,12 +614,12 @@ end
# compute the line segments which should be drawn for this axis
function axis_drawing_info(sp::Subplot)
xaxis, yaxis = sp[:xaxis], sp[:yaxis]
xmin, xmax = axis_limits(xaxis)
ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
xminorticks = get_minor_ticks(xaxis,xticks)
yminorticks = get_minor_ticks(yaxis,yticks)
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
xticks = get_ticks(sp, xaxis)
yticks = get_ticks(sp, yaxis)
xminorticks = get_minor_ticks(sp, xaxis, xticks)
yminorticks = get_minor_ticks(sp, yaxis, yticks)
xaxis_segs = Segments(2)
yaxis_segs = Segments(2)
xtick_segs = Segments(2)
@@ -614,14 +642,14 @@ function axis_drawing_info(sp::Subplot)
end
push!(xaxis_segs, (xmin, y1), (xmax, y1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(xticks in (nothing,false)) && length(xticks) > 1
if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && length(xticks) > 1
showticks = xticks[1] .!= 0
xticks = (xticks[1][showticks], xticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2), (xmax, y2)) # top spine
end
if !(xaxis[:ticks] in (nothing, false))
if !(xaxis[:ticks] in (:none, nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
@@ -642,7 +670,7 @@ function axis_drawing_info(sp::Subplot)
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end
end
if !(xaxis[:minorticks] in (nothing, false)) || xaxis[:minorgrid]
if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid]
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
@@ -675,14 +703,14 @@ function axis_drawing_info(sp::Subplot)
end
push!(yaxis_segs, (x1, ymin), (x1, ymax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(yticks in (nothing,false)) && length(yticks) > 1
if sp[:framestyle] == :origin && !(yticks in (:none, nothing,false)) && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin), (x2, ymax)) # right spine
end
if !(yaxis[:ticks] in (nothing, false))
if !(yaxis[:ticks] in (:none, nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
@@ -703,7 +731,7 @@ function axis_drawing_info(sp::Subplot)
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
if !(yaxis[:minorticks] in (nothing, false)) || yaxis[:minorgrid]
if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid]
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
+371 -128
View File
@@ -7,16 +7,20 @@ const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[]
const _initialized_backends = Set{Symbol}()
const _default_backends = (:none, :gr, :plotly)
const _backendPackage = Dict{Symbol, Symbol}()
const _backend_packages = Dict{Symbol, Symbol}()
"Returns a list of supported backends"
backends() = _backends
"Returns the name of the current backend"
backend_name() = CURRENT_BACKEND.sym
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
backend_package(pkg::Symbol) = pkg in _default_backends ? :Plots : Symbol("Plots", _backendPackage[pkg])
backend_package_name(sym::Symbol) = sym in _default_backends ? :Plots : _backendPackage[sym]
function _backend_instance(sym::Symbol)::AbstractBackend
haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
end
backend_package_name(sym::Symbol) = _backend_packages[sym]
macro init_backend(s)
package_str = string(s)
@@ -26,13 +30,13 @@ macro init_backend(s)
esc(quote
struct $T <: AbstractBackend end
export $sym
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
$sym(; kw...) = (default(; kw...); backend($T()))
backend_name(::$T) = Symbol($str)
backend_package_name(pkg::$T) = backend_package_name(Symbol($str))
push!(_backends, Symbol($str))
_backendType[Symbol($str)] = $T
_backendSymbol[$T] = Symbol($str)
_backendPackage[Symbol($str)] = Symbol($package_str)
_backend_packages[Symbol($str)] = Symbol($package_str)
# include("backends/" * $str * ".jl")
end)
end
@@ -42,12 +46,6 @@ end
# ---------------------------------------------------------
function add_backend(pkg::Symbol)
@info("To do a standard install of $pkg, copy and run this:\n\n")
println(add_backend_string(_backend_instance(pkg)))
println()
end
# don't do anything as a default
_create_backend_figure(plt::Plot) = nothing
_prepare_plot_object(plt::Plot) = nothing
@@ -77,8 +75,8 @@ end
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
# account for the size/length/rotation of tick labels
function tick_padding(axis::Axis)
ticks = get_ticks(axis)
function tick_padding(sp::Subplot, axis::Axis)
ticks = get_ticks(sp, axis)
if ticks == nothing
0mm
else
@@ -108,10 +106,10 @@ end
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot)
# TODO: something different when `is3d(sp) == true`
leftpad = tick_padding(sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
leftpad = tick_padding(sp, sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
toppad = sp[:top_margin] + title_padding(sp)
rightpad = sp[:right_margin]
bottompad = tick_padding(sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
bottompad = tick_padding(sp, sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
# switch them?
if sp[:xaxis][:mirror]
@@ -138,33 +136,22 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
# ---------------------------------------------------------
function pickDefaultBackend()
_fallback_default_backend() = backend(GRBackend())
function _pick_default_backend()
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
if env_default != ""
sym = Symbol(lowercase(env_default))
if sym in _backends
if sym in _initialized_backends
return backend(sym)
else
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
end
backend(sym)
else
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
@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"))
_fallback_default_backend()
end
else
_fallback_default_backend()
end
# the ordering/inclusion of this package list is my semi-arbitrary guess at
# which one someone will want to use if they have the package installed...accounting for
# features, speed, and robustness
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
# if pkgstr in keys(Pkg.installed())
# return backend(Symbol(lowercase(pkgstr)))
# end
# end
# the default if nothing else is installed
backend(:gr)
end
@@ -174,13 +161,11 @@ end
Returns the current plotting package name. Initializes package on first call.
"""
function backend()
if CURRENT_BACKEND.sym == :none
_pick_default_backend()
end
global CURRENT_BACKEND
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
end
CURRENT_BACKEND.pkg
CURRENT_BACKEND.pkg
end
"""
@@ -188,20 +173,13 @@ Set the plot backend.
"""
function backend(pkg::AbstractBackend)
sym = backend_name(pkg)
if sym in _initialized_backends
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
else
# try
_initialize_backend(pkg)
push!(_initialized_backends, sym)
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
# catch
# add_backend(sym)
# end
if !(sym in _initialized_backends)
_initialize_backend(pkg)
push!(_initialized_backends, sym)
end
backend()
CURRENT_BACKEND.sym = sym
CURRENT_BACKEND.pkg = pkg
pkg
end
function backend(sym::Symbol)
@@ -209,15 +187,15 @@ function backend(sym::Symbol)
backend(_backend_instance(sym))
else
@warn("`:$sym` is not a supported backend.")
backend()
end
backend()
end
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize]
function warn_on_deprecated_backend(bsym::Symbol)
if bsym in _deprecated_backends
@warn("Backend $bsym has been deprecated. It may not work as originally intended.")
@warn("Backend $bsym has been deprecated.")
end
end
@@ -268,17 +246,11 @@ end
# @init_backend Immerse
# @init_backend Gadfly
@init_backend PyPlot
# @init_backend Qwt
@init_backend UnicodePlots
# @init_backend Winston
# @init_backend Bokeh
@init_backend Plotly
@init_backend PlotlyJS
@init_backend GR
@init_backend GLVisualize
@init_backend PGFPlots
@init_backend InspectDR
@init_backend HDF5
@@ -322,72 +294,191 @@ function _initialize_backend(pkg::AbstractBackend)
end
end
function add_backend_string(pkg::AbstractBackend)
sym = backend_package_name(pkg)
"""
using Pkg
Pkg.add("$sym")
"""
end
_initialize_backend(pkg::GRBackend) = nothing
_initialize_backend(pkg::PlotlyBackend) = nothing
# ------------------------------------------------------------------------------
# glvisualize
# gr
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval Main begin
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
import FileIO, Images
export GLVisualize
import Reactive: Signal
import GLAbstraction: Style
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
end
end
const _gr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins,
:layout,
:title, :window_title,
:guide, :lims, :ticks, :scale, :flip,
:match_dimensions,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
:legendfontrotation, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
:tickfontrotation, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
:guidefontrotation, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
:fill_z, :line_z, :marker_z, :levels,
:ribbon, :quiver,
:orientation,
:overwrite_figure,
:polar,
:aspect_ratio,
:normalize, :weights,
:inset_subplots,
:bar_width,
:arrow,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _gr_seriestype = [
:path, :scatter, :straightline,
:heatmap, :pie, :image,
:contour, :path3d, :scatter3d, :surface, :wireframe, :volume,
:shape
]
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _gr_marker = _allMarkers
const _gr_scale = [:identity, :log10]
is_marker_supported(::GRBackend, shape::Shape) = true
# ------------------------------------------------------------------------------
# hdf5
# plotly
function _initialize_backend(::HDF5Backend)
@eval Main begin
import HDF5
export HDF5
end
end
const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
:title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title, :colorbar_entry,
:marker_z, :fill_z, :line_z, :levels,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
:polar,
:normalize, :weights,
# :contours,
:aspect_ratio,
:hover,
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _plotly_seriestype = [
:path, :scatter, :pie, :heatmap,
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
:straightline
]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
]
const _plotly_scale = [:identity, :log10]
defaultOutputFormat(plt::Plot{Plots.PlotlyBackend}) = "html"
# ------------------------------------------------------------------------------
# PGFPLOTS
# pgfplots
function add_backend_string(::PGFPlotsBackend)
"""
using Pkg
Pkg.add("PGFPlots")
Pkg.build("PGFPlots")
"""
end
const _pgfplots_attr = merge_with_base_supported([
:annotations,
:background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
# :bar_width, :bar_edges,
:title,
# :window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
:polar,
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
:framestyle,
:camera,
:contour_labels,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
# ------------------------------------------------------------------------------
# plotlyjs
function add_backend_string(::PlotlyJSBackend)
"""
using Pkg
Pkg.add("PlotlyJS")
Pkg.add("Rsvg")
import Blink
Blink.AtomShell.install()
"""
function _initialize_backend(pkg::PlotlyJSBackend)
@eval Main begin
import PlotlyJS, ORCA
export PlotlyJS
end
end
const _plotlyjs_attr = _plotly_attr
const _plotlyjs_seriestype = _plotly_seriestype
const _plotlyjs_style = _plotly_style
const _plotlyjs_marker = _plotly_marker
const _plotlyjs_scale = _plotly_scale
# ------------------------------------------------------------------------------
# pyplot
function _initialize_backend(::PyPlotBackend)
@eval Main begin
import PyPlot, PyCall
import LaTeXStrings
import PyPlot
export PyPlot
@@ -396,25 +487,177 @@ function _initialize_backend(::PyPlotBackend)
end
end
function add_backend_string(::PyPlotBackend)
"""
using Pkg
Pkg.add("PyPlot")
Pkg.add("PyCall")
Pkg.add("LaTeXStrings")
withenv("PYTHON" => "") do
Pkg.build("PyCall")
Pkg.build("PyPlot")
end
"""
end
const _pyplot_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:stride,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
const _pyplot_marker = vcat(_allMarkers, :pixel)
const _pyplot_scale = [:identity, :ln, :log2, :log10]
# ------------------------------------------------------------------------------
# unicodeplots
function add_backend_string(::UnicodePlotsBackend)
"""
using Pkg
Pkg.add("UnicodePlots")
Pkg.build("UnicodePlots")
"""
end
const _unicodeplots_attr = merge_with_base_supported([
:label,
:legend,
:seriescolor,
:seriesalpha,
:linestyle,
:markershape,
:bins,
:title,
:guide, :lims,
])
const _unicodeplots_seriestype = [
:path, :scatter, :straightline,
# :bar,
:shape,
:histogram2d,
:spy
]
const _unicodeplots_style = [:auto, :solid]
const _unicodeplots_marker = [:none, :auto, :circle]
const _unicodeplots_scale = [:identity]
# ------------------------------------------------------------------------------
# hdf5
const _hdf5_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
# ------------------------------------------------------------------------------
# inspectdr
const _inspectdr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location,
:window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :legend, #:colorbar,
# :marker_z,
# :line_z,
# :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
:overwrite_figure,
:polar,
# :normalize, :weights,
# :contours, :aspect_ratio,
:match_dimensions,
# :clims,
# :inset_subplots,
:dpi,
# :colorbar_title,
])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
]
#see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[
:none, :auto,
:circle, :rect, :diamond,
:cross, :xcross,
:utriangle, :dtriangle, :rtriangle, :ltriangle,
:pentagon, :hexagon, :heptagon, :octagon,
:star4, :star5, :star6, :star7, :star8,
:vline, :hline, :+, :x,
]
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
File diff suppressed because it is too large Load Diff
+467 -257
View File
File diff suppressed because it is too large Load Diff
+50 -62
View File
@@ -16,16 +16,19 @@ Read from .hdf5 file using:
#==TODO
===============================================================================
1. Support more features
- SeriesAnnotations & GridLayout known to be missing.
3. Improve error handling.
1. Support more features.
- GridLayout known not to be working.
2. Improve error handling.
- Will likely crash if file format is off.
2. Save data in a folder parallel to "plot".
3. Save data in a folder parallel to "plot".
- Will make it easier for users to locate data.
- Use HDF5 reference to link data?
3. Develop an actual versioned file format.
4. Develop an actual versioned file format.
- Should have some form of backward compatibility.
- Should be reliable for archival purposes.
5. Fix construction of plot object with hdf5plot_read.
- Not building object correctly when backends do not natively support
a certain feature (ex: :steppre)
==#
import FixedPointNumbers: N0f8 #In core Julia
@@ -56,53 +59,13 @@ const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
#Simple sub-structures that can just be written out using _hdf5plot_gwritefields:
const HDF5PLOT_SIMPLESUBSTRUCT = Union{Font, BoundingBox,
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText,
Shape,
}
#==
===============================================================================#
const _hdf5_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::HDF5Backend, shape::Shape) = true
if length(HDF5PLOT_MAP_TELEM2STR) < 1
@@ -125,7 +88,8 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"PLOTTEXT" => PlotText,
"SHAPE" => Shape,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
@@ -284,6 +248,14 @@ end
# ----------------------------------------------------------------
function _hdf5plot_gwrite(grp, k::String, v) #Default
T = typeof(v)
if !(T <: Number || T <: String)
tstr = string(T)
path = HDF5.name(grp) * "/" * k
@info("Type not supported: $tstr\npath: $path")
# @show v
return
end
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
@@ -338,10 +310,6 @@ function _hdf5plot_gwrite(grp, k::String, v::Colorant)
end
#Custom vector (when not using simple numeric type):
function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
if "annotations" == k;
return #Hack. Does not yet support annotations.
end
vgrp = HDF5.g_create(grp, k)
_hdf5plot_writetype(vgrp, Array) #ANY
sz = size(v)
@@ -351,7 +319,7 @@ function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
coord = lidx[iter]
elem = v[iter]
idxstr = join(coord, "_")
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
_hdf5plot_gwrite(vgrp, "v$idxstr", elem)
end
_hdf5plot_gwrite(vgrp, "dim", [sz...])
@@ -402,10 +370,6 @@ end
# return
# end
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
#Currently no support for SeriesAnnotations
return
end
function _hdf5plot_gwrite(grp, k::String, v::Subplot)
grp = HDF5.g_create(grp, k)
_hdf5plot_gwrite(grp, "index", v[:subplot_index])
@@ -528,6 +492,29 @@ function _hdf5plot_read(grp, k::String, T::Type{HDF5CTuple}, dtid)
v = _hdf5plot_read(grp, k, Array, dtid)
return tuple(v...)
end
function _hdf5plot_read(grp, k::String, T::Type{PlotText}, dtid)
grp = HDF5.g_open(grp, k)
str = _hdf5plot_read(grp, "str")
font = _hdf5plot_read(grp, "font")
return PlotText(str, font)
end
function _hdf5plot_read(grp, k::String, T::Type{SeriesAnnotations}, dtid)
grp = HDF5.g_open(grp, k)
strs = _hdf5plot_read(grp, "strs")
font = _hdf5plot_read(grp, "font")
baseshape = _hdf5plot_read(grp, "baseshape")
scalefactor = _hdf5plot_read(grp, "scalefactor")
return SeriesAnnotations(strs, font, baseshape, scalefactor)
end
function _hdf5plot_read(grp, k::String, T::Type{Shape}, dtid)
grp = HDF5.g_open(grp, k)
x = _hdf5plot_read(grp, "x")
y = _hdf5plot_read(grp, "y")
return Shape(x, y)
end
function _hdf5plot_read(grp, k::String, T::Type{ColorGradient}, dtid)
grp = HDF5.g_open(grp, k)
@@ -601,11 +588,6 @@ end
function _hdf5plot_read(sp::Subplot, subpath::String, f)
f = f::HDF5.HDF5File #Assert
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
kwlist = KW()
_hdf5plot_read(grp, kwlist)
_hdf5_merge!(sp.attr, kwlist)
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list"))
nseries = _hdf5plot_readcount(grp)
@@ -617,6 +599,12 @@ function _hdf5plot_read(sp::Subplot, subpath::String, f)
_hdf5_merge!(sp.series_list[end].plotattributes, kwlist)
end
#Perform after adding series... otherwise values get overwritten:
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
kwlist = KW()
_hdf5plot_read(grp, kwlist)
_hdf5_merge!(sp.attr, kwlist)
return
end
+13 -62
View File
@@ -14,59 +14,6 @@ Add in functionality to Plots.jl:
=#
# ---------------------------------------------------------------------------
#TODO: remove features
const _inspectdr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location,
:window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :legend, #:colorbar,
# :marker_z,
# :line_z,
# :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
:overwrite_figure,
:polar,
# :normalize, :weights,
# :contours, :aspect_ratio,
:match_dimensions,
# :clims,
# :inset_subplots,
:dpi,
# :colorbar_title,
])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
]
#see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[
:none, :auto,
:circle, :rect, :diamond,
:cross, :xcross,
:utriangle, :dtriangle, :rtriangle, :ltriangle,
:pentagon, :hexagon, :heptagon, :octagon,
:star4, :star5, :star6, :star7, :star8,
:vline, :hline, :+, :x,
]
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::InspectDRBackend, shape::Shape) = true
@@ -260,8 +207,10 @@ For st in :shape:
nmax = i
if length(rng) > 1
linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
c = plot_color(get_linecolor(series), get_linealpha(series))
linecolor = _inspectdr_mapcolor(_cycle(c, i))
c = plot_color(get_fillcolor(series), get_fillalpha(series))
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
line = InspectDR.line(
style=:solid, width=linewidth, color=linecolor
)
@@ -275,8 +224,10 @@ For st in :shape:
i = (nmax >= 2 ? div(nmax, 2) : nmax) #Must pick one set of colors for legend
if i > 1 #Add dummy waveform for legend entry:
linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
c = plot_color(get_linecolor(series), get_linealpha(series))
linecolor = _inspectdr_mapcolor(_cycle(c, i))
c = plot_color(get_fillcolor(series), get_fillalpha(series))
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
wfrm = InspectDR.add(plot, Float64[], Float64[], id=series[:label])
wfrm.line = InspectDR.line(
style=:none, width=linewidth, #linewidth affects glyph
@@ -295,7 +246,7 @@ For st in :shape:
wfrm.line = InspectDR.line(
style = _style,
width = series[:linewidth],
color = series[:linecolor],
color = plot_color(get_linecolor(series), get_linealpha(series)),
)
#InspectDR does not control markerstrokewidth independently.
if :none == _style
@@ -305,8 +256,8 @@ For st in :shape:
wfrm.glyph = InspectDR.glyph(
shape = _inspectdr_mapglyph(series[:markershape]),
size = _inspectdr_mapglyphsize(series[:markersize]),
color = _inspectdr_mapcolor(series[:markerstrokecolor]),
fillcolor = _inspectdr_mapcolor(series[:markercolor]),
color = _inspectdr_mapcolor(plot_color(series[:markerstrokecolor], series[:markerstrokealpha])),
fillcolor = _inspectdr_mapcolor(plot_color(series[:markercolor], series[:markeralpha])),
)
end
@@ -343,8 +294,8 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(xaxis)
ymin, ymax = axis_limits(yaxis)
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
if ispolar(sp)
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
rmax = NaNMath.max(abs(ymin), abs(ymax))
+26 -54
View File
@@ -2,47 +2,6 @@
# significant contributions by: @pkofod
const _pgfplots_attr = merge_with_base_supported([
:annotations,
:background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
# :bar_width, :bar_edges,
:title,
# :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
:polar,
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
:framestyle,
:camera,
:contour_labels,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
# --------------------------------------------------------------------------------------
const _pgfplots_linestyles = KW(
@@ -67,7 +26,8 @@ const _pgfplots_markers = KW(
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*",
:hline => "-"
:hline => "-",
:vline => "|"
)
const _pgfplots_legend_pos = KW(
@@ -211,7 +171,7 @@ function pgf_series(sp::Subplot, series::Series)
elseif st == :shape
shape_data(series)
elseif ispolar(sp)
theta, r = filter_radial_data(plotattributes[:x], plotattributes[:y], axis_limits(sp[:yaxis]))
theta, r = plotattributes[:x], plotattributes[:y]
rad2deg.(theta), r
else
plotattributes[:x], plotattributes[:y]
@@ -364,9 +324,17 @@ function pgf_axis(sp::Subplot, letter)
# axis guide
kw[Symbol(letter,:label)] = axis[:guide]
# axis label position
labelpos = ""
if letter == :x && axis[:guide_position] == :top
labelpos = "at={(0.5,1)},above,"
elseif letter == :y && axis[:guide_position] == :right
labelpos = "at={(1,0.5)},below,"
end
# 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], "}"))
push!(style, string(letter, "label style = {", labelpos ,"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")
@@ -393,19 +361,19 @@ function pgf_axis(sp::Subplot, letter)
# limits
# TODO: support zlims
if letter != :z
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
ticks = get_ticks(axis)
ticks = get_ticks(sp, axis)
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = Vector{String}(length(ticks[2]))
tick_labels = Vector{String}(undef, length(ticks[2]))
for (i, label) in enumerate(ticks[2])
base, power = split(label, "^")
power = string("{", power, "}")
@@ -416,7 +384,7 @@ function pgf_axis(sp::Subplot, letter)
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
if axis[:formatter] in (:scientific, :auto)
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
tick_labels = replace.(tick_labels, "×", "\\times")
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
end
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
else
@@ -431,14 +399,18 @@ function pgf_axis(sp::Subplot, letter)
# framestyle
if framestyle in (:axes, :origin)
axispos = framestyle == :axes ? "left" : "middle"
# the * after lines disables the arrows at the axes
push!(style, string("axis lines* = ", axispos))
if axis[:draw_arrow]
push!(style, string("axis ", letter, " line = ", axispos))
else
# the * after line disables the arrow at the axis
push!(style, string("axis ", letter, " line* = ", axispos))
end
end
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}"))
end
if !axis[:showaxis]
@@ -447,7 +419,7 @@ function pgf_axis(sp::Subplot, letter)
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), "}"))
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}"))
end
# return the style list and KW args
@@ -555,7 +527,7 @@ 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!.(Ref(o), pgf_series(sp, series))
# add series annotations
anns = series[:series_annotations]
@@ -596,7 +568,7 @@ end
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
fn = tempname()*".tex"
PGFPlots.save(fn, backend_object(plt), include_preamble=false)
PGFPlots.save(fn, backend_object(plt), include_preamble=plt.attr[:tex_output_standalone])
write(io, read(open(fn), String))
end
+59 -117
View File
@@ -1,60 +1,6 @@
# https://plot.ly/javascript/getting-started
const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
:title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :line_z, :levels,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
:polar,
:normalize, :weights,
# :contours,
:aspect_ratio,
:hover,
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _plotly_seriestype = [
:path, :scatter, :pie, :heatmap,
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
:straightline
]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
]
const _plotly_scale = [:identity, :log10]
is_subplot_supported(::PlotlyBackend) = true
# is_string_supported(::PlotlyBackend) = true
const _plotly_framestyles = [:box, :axes, :zerolines, :grid, :none]
@@ -71,30 +17,9 @@ end
# --------------------------------------------------------------------------------------
const plotly_remote_file_path = "https://cdn.plot.ly/plotly-latest.min.js"
const _plotly_js_path = joinpath(dirname(@__FILE__), "..", "..", "deps", "plotly-latest.min.js")
const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
_js_code = open(read, _plotly_js_path, "r")
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
_js_script = """
<script type='text/javascript'>
define('plotly', function(require, exports, module) {
$(_js_code)
});
require(['plotly'], function(Plotly) {
window.Plotly = Plotly;
});
</script>
"""
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
display("text/html", _js_script)
end
# if isatom()
# import Atom
# Atom.@msg evaljs(_js_code)
@@ -102,8 +27,6 @@ end
using UUIDs
push!(_initialized_backends, :plotly)
# ----------------------------------------------------------------
const _plotly_legend_pos = KW(
@@ -115,7 +38,7 @@ const _plotly_legend_pos = KW(
:bottomright => [1., 0.],
:topright => [1., 1.],
:topleft => [0., 1.]
)
)
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
@@ -191,8 +114,8 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
if aspect_ratio == :equal
aspect_ratio = 1.0
end
xmin,xmax = axis_limits(sp[:xaxis])
ymin,ymax = axis_limits(sp[:yaxis])
xmin,xmax = axis_limits(sp, :x)
ymin,ymax = axis_limits(sp, :y)
want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio
parea_ratio = width(plotarea) / height(plotarea)
if want_ratio > parea_ratio
@@ -251,7 +174,7 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
ax[:tickangle] = -axis[:rotation]
ax[:type] = plotly_scale(axis[:scale])
lims = axis_limits(axis)
lims = axis_limits(sp, letter)
if axis[:ticks] != :native || axis[:lims] != :auto
ax[:range] = map(scalefunc(axis[:scale]), lims)
@@ -263,14 +186,9 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
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[:range] = reverse(ax[:range])
end
# ticks
if axis[:ticks] != :native
ticks = get_ticks(axis)
ticks = get_ticks(sp, axis)
ttype = ticksType(ticks)
if ttype == :ticks
ax[:tickmode] = "array"
@@ -285,20 +203,24 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
ax[:showgrid] = false
end
# flip
if axis[:flip]
ax[:range] = reverse(ax[:range])
end
ax
end
function plotly_polaraxis(axis::Axis)
function plotly_polaraxis(sp::Subplot, axis::Axis)
ax = KW(
:visible => axis[:showaxis],
:showline => axis[:grid],
)
if axis[:letter] == :x
ax[:range] = rad2deg.(axis_limits(axis))
ax[:range] = rad2deg.(axis_limits(sp, :x))
else
ax[:range] = axis_limits(axis)
ax[:range] = axis_limits(sp, :y)
ax[:orientation] = -90
end
@@ -361,8 +283,8 @@ function plotly_layout(plt::Plot)
),
)
elseif ispolar(sp)
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis])
else
plotattributes_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
# don't allow yaxis to be reupdated/reanchored in a linked subplot
@@ -432,7 +354,7 @@ end
function plotly_colorscale(grad::ColorGradient, α)
[[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in 1:length(grad.colors)]
end
plotly_colorscale(c, α) = plotly_colorscale(cgrad(alpha=α), α)
plotly_colorscale(c::Colorant,α) = plotly_colorscale(_as_gradient(c),α)
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], α))]]
@@ -514,7 +436,7 @@ plotly_native_data(axis::Axis, a::Surface) = Surface(plotly_native_data(axis, a.
function plotly_convert_to_datetime(x::AbstractArray, formatter::Function)
if formatter == datetimeformatter
map(xi -> replace(formatter(xi), "T", " "), x)
map(xi -> replace(formatter(xi), "T" => " "), x)
elseif formatter == dateformatter
map(xi -> string(formatter(xi), " 00:00:00"), x)
elseif formatter == timeformatter
@@ -573,7 +495,7 @@ function plotly_series(plt::Plot, series::Series)
# set the "type"
if st in (:path, :scatter, :scattergl, :straightline, :path3d, :scatter3d)
return plotly_series_segments(series, plotattributes, x, y, z, clims)
return plotly_series_segments(series, plotattributes_out, x, y, z, clims)
elseif st == :heatmap
x = heatmap_edges(x, sp[:xaxis][:scale])
@@ -584,13 +506,13 @@ function plotly_series(plt::Plot, series::Series)
plotattributes_out[:showscale] = hascolorbar(sp)
elseif st == :contour
filled = isfilledcontour(series)
plotattributes_out[:type] = "contour"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
# plotattributes_out[:showscale] = series[:colorbar] != :none
plotattributes_out[:ncontours] = series[:levels]
plotattributes_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
plotattributes_out[:ncontours] = series[:levels] + 2
plotattributes_out[:contours] = KW(:coloring => filled ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
plotattributes_out[:showscale] = hascolorbar(sp)
plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series)
elseif st in (:surface, :wireframe)
plotattributes_out[:type] = "surface"
@@ -678,7 +600,7 @@ function plotly_series_shapes(plt::Plot, series::Series, clims)
:fillcolor => rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))),
))
if series[:markerstrokewidth] > 0
plotattributes[:line] = KW(
plotattributes_out[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:dash => string(get_linestyle(series, i)),
@@ -699,7 +621,7 @@ function plotly_series_shapes(plt::Plot, series::Series, clims)
plotattributes_outs
end
function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z, clims)
function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z, clims)
st = series[:seriestype]
sp = series[:subplot]
isscatter = st in (:scatter, :scatter3d, :scattergl)
@@ -727,11 +649,11 @@ function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z,
hasline ? "lines" : "none"
end
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
plotattributes[:fill] = "tozeroy"
plotattributes[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
plotattributes_out[:fill] = "tozeroy"
plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
plotattributes[:fill] = "tonexty"
plotattributes[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
plotattributes_out[:fill] = "tonexty"
plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, 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
@@ -763,7 +685,7 @@ function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z,
# add "line"
if hasline
plotattributes[:line] = KW(
plotattributes_out[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:shape => if st == :steppre
@@ -852,7 +774,7 @@ end
function plotly_polar!(plotattributes_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(series[:subplot])
theta, r = filter_radial_data(pop!(plotattributes_out, :x), pop!(plotattributes_out, :y), axis_limits(series[:subplot][:yaxis]))
theta, r = pop!(plotattributes_out, :x), pop!(plotattributes_out, :y)
plotattributes_out[:t] = rad2deg.(theta)
plotattributes_out[:r] = r
end
@@ -882,12 +804,27 @@ plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt))
# ----------------------------------------------------------------
const _use_remote = Ref(false)
const ijulia_initialized = Ref(false)
function html_head(plt::Plot{PlotlyBackend})
jsfilename = _use_remote[] ? _plotly_js_path_remote : ("file://" * _plotly_js_path)
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
"<script src=\"$jsfilename\"></script>"
local_file = ("file://" * plotly_local_file_path)
plotly = use_local_dependencies[] ? local_file : plotly_remote_file_path
if isijulia() && !ijulia_initialized[]
# using requirejs seems to be key to load a js depency in IJulia!
# https://requirejs.org/docs/start.html
# https://github.com/JuliaLang/IJulia.jl/issues/345
display("text/html", """
<script type="text/javascript">
requirejs([$(repr(plotly))], function(p) {
window.Plotly = p
});
</script>
""")
ijulia_initialized[] = true
end
# IJulia just needs one initialization
isijulia() && return ""
return "<script src=$(repr(plotly))></script>"
end
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
@@ -908,19 +845,24 @@ end
function js_body(plt::Plot{PlotlyBackend}, uuid)
js = """
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
"""
end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, html_head(plt) * html_body(plt))
function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{PlotlyBackend})
data = []
for series in plot.series_list
append!(data, plotly_series(plot, series))
end
layout = plotly_layout(plot)
JSON.print(io, Dict(:data => data, :layout => layout))
end
function _display(plt::Plot{PlotlyBackend})
standalone_html_window(plt)
end
+10 -24
View File
@@ -1,18 +1,11 @@
# https://github.com/spencerlyon2/PlotlyJS.jl
const _plotlyjs_attr = _plotly_attr
const _plotlyjs_seriestype = _plotly_seriestype
const _plotlyjs_style = _plotly_style
const _plotlyjs_marker = _plotly_marker
const _plotlyjs_scale = _plotly_scale
# https://github.com/sglyon/PlotlyJS.jl
# --------------------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
PlotlyJS.SyncPlot(PlotlyJS.Plot(), options = current().o.options)
else
PlotlyJS.plot()
end
@@ -56,23 +49,16 @@ end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else
show(io, MIME("text/html"), plt.o)
end
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = show(io, MIME("text/html"), plt.o)
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="eps")
function _show(io::IO, m::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend})
show(io, m, plt.o)
end
function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
tmpfn = tempname() * "." * ext
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
function write_temp_html(plt::Plot{PlotlyJSBackend})
filename = string(tempname(), ".html")
+314 -246
View File
File diff suppressed because it is too large Load Diff
+3 -25
View File
@@ -1,28 +1,6 @@
# https://github.com/Evizero/UnicodePlots.jl
const _unicodeplots_attr = merge_with_base_supported([
:label,
:legend,
:seriescolor,
:seriesalpha,
:linestyle,
:markershape,
:bins,
:title,
:guide, :lims,
])
const _unicodeplots_seriestype = [
:path, :scatter, :straightline,
# :bar,
:shape,
:histogram2d,
:spy
]
const _unicodeplots_style = [:auto, :solid]
const _unicodeplots_marker = [:none, :auto, :circle]
const _unicodeplots_scale = [:identity]
# don't warn on unsupported... there's just too many warnings!!
warnOnUnsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
@@ -49,8 +27,8 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
for sp in plt.subplots
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xlim = axis_limits(xaxis)
ylim = axis_limits(yaxis)
xlim = axis_limits(sp, :x)
ylim = axis_limits(sp, :y)
# make vectors
xlim = [xlim[1], xlim[2]]
@@ -138,7 +116,7 @@ function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
x, y = if st == :straightline
straightline_data(plotattributes)
elseif st == :shape
shape_data(series)
shape_data(plotattributes)
else
[collect(float(plotattributes[s])) for s in (:x, :y)]
end
+6
View File
@@ -42,8 +42,14 @@ function write_temp_html(plt::AbstractPlot)
end
function standalone_html_window(plt::AbstractPlot)
old = use_local_dependencies[] # save state to restore afterwards
# if we open a browser ourself, we can host local files, so
# when we have a local plotly downloaded this is the way to go!
use_local_dependencies[] = isfile(plotly_local_file_path)
filename = write_temp_html(plt)
open_browser_window(filename)
# restore for other backends
use_local_dependencies[] = old
end
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
+56 -16
View File
@@ -1,7 +1,7 @@
const P2 = FixedSizeArrays.Vec{2,Float64}
const P3 = FixedSizeArrays.Vec{3,Float64}
const P2 = GeometryTypes.Point2{Float64}
const P3 = GeometryTypes.Point3{Float64}
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
@@ -256,8 +256,24 @@ mutable struct Font
color::Colorant
end
"Create a Font from a list of unordered features"
function font(args...)
"""
font(args...)
Create a Font from a list of features. Values may be specified either as
arguments (which are distinguished by type/value) or as keyword arguments.
# Arguments
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
- `pointsize`: Integer. Size of font in points
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
- `color`: Colorant or Symbol
# Examples
```julia-repl
julia> font(8)
julia> font(family="serif",halign=:center,rotation=45.0)
```
"""
function font(args...;kw...)
# defaults
family = "sans-serif"
@@ -301,6 +317,32 @@ function font(args...)
end
end
for symbol in keys(kw)
if symbol == :family
family = kw[:family]
elseif symbol == :pointsize
pointsize = kw[:pointsize]
elseif symbol == :halign
halign = kw[:halign]
if halign == :center
halign = :hcenter
end
@assert halign in (:hcenter, :left, :right)
elseif symbol == :valign
valign = kw[:valign]
if valign == :center
valign = :vcenter
end
@assert valign in (:vcenter, :top, :bottom)
elseif symbol == :rotation
rotation = kw[:rotation]
elseif symbol == :color
color = parse(Colorant, kw[:color])
else
@warn("Unused font kwarg: $symbol")
end
end
Font(family, pointsize, halign, valign, rotation, color)
end
@@ -344,15 +386,16 @@ end
PlotText(str) = PlotText(string(str), font())
"""
text(string, args...)
text(string, args...; kw...)
Create a PlotText object wrapping a string with font info, for plot annotations
Create a PlotText object wrapping a string with font info, for plot annotations.
`args` and `kw` are passed to `font`.
"""
text(t::PlotText) = t
text(t::PlotText, font::Font) = PlotText(t.str, font)
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
PlotText(string(str), font(args...))
function text(str, args...;kw...)
PlotText(string(str), font(args...;kw...))
end
Base.length(t::PlotText) = length(t.str)
@@ -491,7 +534,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# with a list of custom shapes for each
msw,msh = anns.scalefactor
msize = Float64[]
shapes = Vector{Shape}(length(anns.strs))
shapes = Vector{Shape}(undef, length(anns.strs))
for i in eachindex(anns.strs)
str = _cycle(anns.strs,i)
@@ -509,7 +552,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# and then re-scale a copy of baseshape to match the w/h ratio
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = _cycle(get(anns.baseshape),i)
baseshape = _cycle(anns.baseshape, i)
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end
series[:markershape] = shapes
@@ -554,7 +597,7 @@ function process_annotation(sp::Subplot, xs, ys, labs, font = font())
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (x, y, isa(lab, PlotText) ? lab : text(lab, font)))
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
end
end
anns
@@ -569,7 +612,7 @@ function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol},
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font)))
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
end
end
anns
@@ -736,7 +779,7 @@ end
# -----------------------------------------------------------------------
"create a BezierCurve for plotting"
mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
mutable struct BezierCurve{T <: GeometryTypes.Point}
control_points::Vector{T}
end
@@ -749,9 +792,6 @@ function (bc::BezierCurve)(t::Real)
p
end
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
# mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
@deprecate curve_points coords
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, range(range..., stop=n, length=50))
-208
View File
@@ -1,208 +0,0 @@
# https://github.com/bokeh/Bokeh.jl
supported_attrs(::BokehBackend) = merge_with_base_supported([
# :annotations,
# :axis,
# :background_color,
:linecolor,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
:group,
# :label,
# :layout,
# :legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
:linewidth,
# :linealpha,
:markershape,
:markercolor,
:markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :bins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
:size,
:title,
# :window_title,
:x,
# :xguide,
# :xlims,
# :xticks,
:y,
# :yguide,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface,
# :levels,
])
supported_types(::BokehBackend) = [:path, :scatter]
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::BokehBackend) = [:identity, :ln]
is_subplot_supported(::BokehBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::BokehBackend; kw...)
@eval begin
@warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
end
const _glyphtypes = KW(
:circle => :Circle,
:rect => :Square,
:diamond => :Diamond,
:utriangle => :Triangle,
:dtriangle => :InvertedTriangle,
# :pentagon =>
# :hexagon =>
# :heptagon =>
# :octagon =>
:cross => :Cross,
:xcross => :X,
:star5 => :Asterisk,
)
function bokeh_glyph_type(plotattributes::KW)
st = plotattributes[:seriestype]
mt = plotattributes[:markershape]
if st == :scatter && mt == :none
mt = :circle
end
# if we have a marker, use that
if st == :scatter || mt != :none
return _glyphtypes[mt]
end
# otherwise return a line
return :Line
end
function get_stroke_vector(linestyle::Symbol)
dash = 12
dot = 3
gap = 2
linestyle == :solid && return Int[]
linestyle == :dash && return Int[dash, gap]
linestyle == :dot && return Int[dot, gap]
linestyle == :dashdot && return Int[dash, gap, dot, gap]
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
error("unsupported linestyle: ", linestyle)
end
# ---------------------------------------------------------------------------
# function _create_plot(pkg::BokehBackend, plotattributes::KW)
function _create_backend_figure(plt::Plot{BokehBackend})
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
datacolumns = Bokeh.BokehDataSet[]
tools = Bokeh.tools()
filename = tempname() * ".html"
title = plt.attr[:title]
w, h = plt.attr[:size]
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
# legend = plt.attr[:legend] ? xxxx : nothing
legend = nothing
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
# Plot(bplt, pkg, 0, plotattributes, KW[])
end
# function _series_added(::BokehBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{BokehBackend}, series::Series)
bdata = Dict{Symbol, Vector}(:x => collect(series.plotattributes[:x]), :y => collect(series.plotattributes[:y]))
glyph = Bokeh.Bokehjs.Glyph(
glyphtype = bokeh_glyph_type(plotattributes),
linecolor = webcolor(plotattributes[:linecolor]), # shape's stroke or line color
linewidth = plotattributes[:linewidth], # shape's stroke width or line width
fillcolor = webcolor(plotattributes[:markercolor]),
size = ceil(Int, plotattributes[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
dash = get_stroke_vector(plotattributes[:linestyle])
)
legend = nothing # TODO
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
# push!(plt.seriesargs, plotattributes)
# plt
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot_object(plt::Plot{BokehBackend}, plotattributes::KW)
end
# ----------------------------------------------------------------
# accessors for x/y data
# function getxy(plt::Plot{BokehBackend}, i::Int)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y]
# end
#
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y] = xy
# plt
# end
# ----------------------------------------------------------------
# ----------------------------------------------------------------
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
# TODO: write a png to io
@warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
Bokeh.showplot(plt.o)
end
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
# # TODO: display/show the subplot
# end
-744
View File
@@ -1,744 +0,0 @@
# https://github.com/dcjones/Gadfly.jl
supported_attrs(::GadflyBackend) = merge_with_base_supported([
:annotations,
:background_color, :foreground_color, :color_palette,
:group, :label, :seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :n, :nc, :nr, :layout, :smooth,
:title, :window_title, :show, :size,
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
:z,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :levels,
:xerror, :yerror,
:ribbon, :quiver,
:orientation,
])
supported_types(::GadflyBackend) = [
:path,
:scatter, :hexbin,
:bar,
:contour, :shape
]
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
is_subplot_supported(::GadflyBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::GadflyBackend; kw...)
@eval begin
import Gadfly, Compose
export Gadfly, Compose
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
end
end
# ---------------------------------------------------------------------------
# immutable MissingVec <: AbstractVector{Float64} end
# Base.size(v::MissingVec) = (1,)
# Base.getindex(v::MissingVec, i::Integer) = 0.0
function createGadflyPlotObject(plotattributes::KW)
gplt = Gadfly.Plot()
gplt.mapping = Dict()
gplt.data_source = Gadfly.DataFrames.DataFrame()
# gplt.layers = gplt.layers[1:0]
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(plotattributes[:xguide]),
Gadfly.Guide.ylabel(plotattributes[:yguide]),
Gadfly.Guide.title(plotattributes[:title])]
gplt
end
# ---------------------------------------------------------------------------
function getLineGeom(plotattributes::KW)
st = plotattributes[:seriestype]
xbins, ybins = maketuple(plotattributes[:bins])
if st == :hexb
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
elseif st == :histogram2d
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
elseif st == :histogram
Gadfly.Geom.histogram(bincount = xbins,
orientation = isvertical(plotattributes) ? :vertical : :horizontal,
position = plotattributes[:bar_position] == :stack ? :stack : :dodge)
elseif st == :path
Gadfly.Geom.path
elseif st in (:bar, :sticks)
Gadfly.Geom.bar
elseif st == :steppost
Gadfly.Geom.step
elseif st == :steppre
Gadfly.Geom.step(direction = :vh)
elseif st == :hline
Gadfly.Geom.hline
elseif st == :vline
Gadfly.Geom.vline
elseif st == :contour
Gadfly.Geom.contour(levels = plotattributes[:levels])
# elseif st == :shape
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
nothing
end
end
function get_extra_theme_args(plotattributes::KW, k::Symbol)
# gracefully handles old Gadfly versions
extra_theme_args = KW()
try
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(plotattributes[k])
catch err
if string(err) == "UndefVarError(:get_stroke_vector)"
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
else
rethrow()
end
end
extra_theme_args
end
function getGadflyLineTheme(plotattributes::KW)
st = plotattributes[:seriestype]
lc = convertColor(getColor(plotattributes[:linecolor]), plotattributes[:linealpha])
fc = convertColor(getColor(plotattributes[:fillcolor]), plotattributes[:fillalpha])
Gadfly.Theme(;
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
line_width = (st == :sticks ? 1 : plotattributes[:linewidth]) * Gadfly.px,
# line_style = Gadfly.get_stroke_vector(plotattributes[:linestyle]),
lowlight_color = x->RGB(fc), # fill/ribbon
lowlight_opacity = alpha(fc), # fill/ribbon
bar_highlight = RGB(lc), # bars
get_extra_theme_args(plotattributes, :linestyle)...
)
end
# add a line as a new layer
function addGadflyLine!(plt::Plot, numlayers::Int, plotattributes::KW, geoms...)
gplt = getGadflyContext(plt)
gfargs = vcat(geoms..., getGadflyLineTheme(plotattributes))
kwargs = KW()
st = plotattributes[:seriestype]
# add a fill?
if plotattributes[:fillrange] != nothing && st != :contour
fillmin, fillmax = map(makevec, maketuple(plotattributes[:fillrange]))
nmin, nmax = length(fillmin), length(fillmax)
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
push!(gfargs, Gadfly.Geom.ribbon)
end
if st in (:hline, :vline)
kwargs[st == :hline ? :yintercept : :xintercept] = plotattributes[:y]
else
if st == :sticks
w = 0.01 * mean(diff(plotattributes[:x]))
kwargs[:xmin] = plotattributes[:x] - w
kwargs[:xmax] = plotattributes[:x] + w
elseif st == :contour
kwargs[:z] = plotattributes[:z].surf
addGadflyContColorScale(plt, plotattributes[:linecolor])
end
kwargs[:x] = plotattributes[st == :histogram ? :y : :x]
kwargs[:y] = plotattributes[:y]
end
# # add the layer
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
get_shape(sym::Symbol) = _shapes[sym]
get_shape(shape::Shape) = shape
# extract the underlying ShapeGeometry object(s)
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
getMarkerGeom(other) = gadflyshape(get_shape(other))
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
function getMarkerGeom(plotattributes::KW)
if plotattributes[:seriestype] == :shape
Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
getMarkerGeom(plotattributes[:markershape])
end
end
function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
c = getColor(plotattributes[:markercolor])
α = plotattributes[:markeralpha]
if α != nothing
c = RGBA(RGB(c), α)
end
ms = plotattributes[:markersize]
ms = if typeof(ms) <: AVec
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
mean(ms) * Gadfly.px
else
ms * Gadfly.px
end
Gadfly.Theme(;
default_color = c,
default_point_size = ms,
discrete_highlight_color = c -> RGB(getColor(plotattributes[:markerstrokecolor])),
highlight_width = plotattributes[:markerstrokewidth] * Gadfly.px,
line_width = plotattributes[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(plotattributes, :markerstrokestyle)...
)
end
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
plt.attr[:colorbar] == :none && return
if !isa(c, ColorGradient)
c = default_gradient()
end
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
end
function addGadflyMarker!(plt::Plot, numlayers::Int, plotattributes::KW, attr::KW, geoms...)
gfargs = vcat(geoms..., getGadflyMarkerTheme(plotattributes, attr), getMarkerGeom(plotattributes))
kwargs = KW()
# handle continuous color scales for the markers
zcolor = plotattributes[:marker_z]
if zcolor != nothing && typeof(zcolor) <: AVec
kwargs[:color] = zcolor
addGadflyContColorScale(plt, plotattributes[:markercolor])
end
Gadfly.layer(gfargs...; x = plotattributes[:x], y = plotattributes[:y], order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
function addToGadflyLegend(plt::Plot, plotattributes::KW)
if plt.attr[:legend] != :none && plotattributes[:label] != ""
gplt = getGadflyContext(plt)
# add the legend if needed
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
pushfirst!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
end
# now add the series to the legend
for guide in gplt.guides
if isa(guide, Gadfly.Guide.ManualColorKey)
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
# since gadfly will call unique(colors), but doesn't also merge the rows that match
# Should ensure from this side that colors which are the same are merged together
c = getColor(plotattributes[plotattributes[:markershape] == :none ? :linecolor : :markercolor])
foundit = false
# extend the label if we found this color
for i in 1:length(guide.colors)
if RGB(c) == guide.colors[i]
guide.labels[i] *= ", " * plotattributes[:label]
foundit = true
end
end
# didn't find the color, so add a new entry into the legend
if !foundit
push!(guide.labels, plotattributes[:label])
push!(guide.colors, c)
end
end
end
end
end
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
function addGadflySeries!(plt::Plot, plotattributes::KW)
layers = Gadfly.Layer[]
gplt = getGadflyContext(plt)
# add a regression line?
# TODO: make more flexible
smooth = getGadflySmoothing(plotattributes[:smooth])
# lines
geom = getLineGeom(plotattributes)
if geom != nothing
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), plotattributes, geom, smooth...))
smooth = Any[] # don't add a regression for markers too
end
# special handling for ohlc and scatter
st = plotattributes[:seriestype]
# if st == :ohlc
# error("Haven't re-implemented after refactoring")
if st in (:histogram2d, :hexbin) && (isa(plotattributes[:fillcolor], ColorGradient) || isa(plotattributes[:fillcolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(plotattributes[:fillcolor], p))))
elseif st == :scatter && plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
# markers
if plotattributes[:markershape] != :none || st == :shape
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), plotattributes, plt.attr, smooth...))
end
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, plotattributes)
# now save the layers that apply to this series
plotattributes[:gadflylayers] = layers
prepend!(gplt.layers, layers)
end
# ---------------------------------------------------------------------------
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
# # colorgroup
# z = plotattributes[:z]
# # handle line segments of different colors
# cscheme = plotattributes[:linecolor]
# if isa(cscheme, ColorVector)
# # create a color scale, and set the color group to the index of the color
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
# # 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(plotattributes[:y])]
# cs = collect(repeat(csindices', 2, 1))[1:end-1]
# grp = collect(repeat((1:length(plotattributes[:y]))', 2, 1))[1:end-1]
# plotattributes[:x], plotattributes[:y] = map(createSegments, (plotattributes[:x], plotattributes[:y]))
# colorgroup = [(:linecolor, cs), (:group, grp)]
# ---------------------------------------------------------------------------
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
ticks == :auto && return
# remove the ticks?
if ticks in (:none, false, nothing)
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
end
ttype = ticksType(ticks)
# just the values... put ticks here, but use standard labels
if ttype == :ticks
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
# set the ticks and the labels
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
elseif ttype == :ticks_and_labels
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
# # TODO add xtick_label function (given tick, return label??)
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
# filterGadflyScale(gplt, isx)
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
# labelmap = Dict(zip(ticks...))
# labelfunc = val -> labelmap[val]
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
filterGadflyScale(gplt, isx)
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
labelmap = Dict(zip(ticks...))
labelfunc = val -> labelmap[val]
push!(gplt.scales, gfunc(labels = labelfunc))
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
end
end
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
scalekey = isx ? :xscale : :yscale
hasScaleKey = haskey(plotattributes, scalekey)
if hasScaleKey
scale = plotattributes[scalekey]
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
end
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
end
function addGadflyLimitsScale(gplt, plotattributes::KW, isx::Bool)
gfunc, hasScaleKey, func = getGadflyScaleFunction(plotattributes, isx)
# do we want to add min/max limits for the axis?
limsym = isx ? :xlims : :ylims
limargs = Any[]
# map :auto to nothing, otherwise add to limargs
lims = get(plotattributes, limsym, :auto)
if lims == :auto
lims = nothing
else
if limsType(lims) == :limits
push!(limargs, (:minvalue, min(lims...)))
push!(limargs, (:maxvalue, max(lims...)))
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
end
end
# replace any current scales with this one
if hasScaleKey || !isempty(limargs)
filterGadflyScale(gplt, isx)
push!(gplt.scales, gfunc(; limargs...))
end
lims, func
end
function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yfunc)
if isa(gplt.coord, Gadfly.Coord.Cartesian)
gplt.coord = Gadfly.Coord.cartesian(
gplt.coord.xvars,
gplt.coord.yvars;
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
xflip = get(plotattributes, :xflip, gplt.coord.xflip),
yflip = get(plotattributes, :yflip, gplt.coord.yflip),
fixed = gplt.coord.fixed,
aspect_ratio = gplt.coord.aspect_ratio,
raster = gplt.coord.raster
)
else
gplt.coord = Gadfly.Coord.Cartesian(
xflip = get(plotattributes, :xflip, false),
yflip = get(plotattributes, :yflip, false)
)
end
end
function findGuideAndSet(gplt, t::DataType, args...; kw...)
for (i,guide) in enumerate(gplt.guides)
if isa(guide, t)
gplt.guides[i] = t(args...; kw...)
end
end
end
function updateGadflyGuides(plt::Plot, plotattributes::KW)
gplt = getGadflyContext(plt)
haskey(plotattributes, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(plotattributes[:title]))
haskey(plotattributes, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(plotattributes[:xguide]))
haskey(plotattributes, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(plotattributes[:yguide]))
xlims, xfunc = addGadflyLimitsScale(gplt, plotattributes, true)
ylims, yfunc = addGadflyLimitsScale(gplt, plotattributes, false)
ticks = get(plotattributes, :xticks, :auto)
if ticks == :none
_remove_axis(plt, true)
else
addGadflyTicksGuide(gplt, ticks, true)
end
ticks = get(plotattributes, :yticks, :auto)
if ticks == :none
_remove_axis(plt, false)
else
addGadflyTicksGuide(gplt, ticks, false)
end
updateGadflyAxisFlips(gplt, plotattributes, xlims, ylims, xfunc, yfunc)
end
function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
kwargs = KW()
# colors
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
map(s -> getColor(plotattributes[s]), (
:background_color_inside,
:foreground_color_grid,
:foreground_color_text,
:foreground_color_guide,
:foreground_color_legend
))
# # hide the legend?
leg = plotattributes[plotattributes[:legend] == :none ? :colorbar : :legend]
if leg != :best
kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(plotattributes, :grid, true)
kwargs[:grid_color] = gridcolor
end
# fonts
tfont, gfont, lfont = plotattributes[:tickfont], plotattributes[:guidefont], plotattributes[:legendfont]
getGadflyContext(plt).theme = Gadfly.Theme(;
background_color = insidecolor,
minor_label_color = textcolor,
minor_label_font = tfont.family,
minor_label_font_size = tfont.pointsize * Gadfly.pt,
major_label_color = guidecolor,
major_label_font = gfont.family,
major_label_font_size = gfont.pointsize * Gadfly.pt,
key_title_color = guidecolor,
key_title_font = gfont.family,
key_title_font_size = gfont.pointsize * Gadfly.pt,
key_label_color = legendcolor,
key_label_font = lfont.family,
key_label_font_size = lfont.pointsize * Gadfly.pt,
plot_padding = 1 * Gadfly.mm,
kwargs...
)
end
# ----------------------------------------------------------------
function createGadflyAnnotationObject(x, y, val::AbstractString)
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, val)
))
end
function createGadflyAnnotationObject(x, y, txt::PlotText)
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, txt.str, halign, valign, rotations...),
Compose.font(string(txt.font.family)),
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
Compose.stroke(txt.font.color),
Compose.fill(txt.font.color)
))
end
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
end
# ---------------------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::GadflyBackend, plotattributes::KW)
# gplt = createGadflyPlotObject(plotattributes)
# Plot(gplt, pkg, 0, plotattributes, KW[])
# end
function _create_backend_figure(plt::Plot{GadflyBackend})
createGadflyPlotObject(plt.attr)
end
# plot one data series
# function _series_added(::GadflyBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{GadflyBackend}, series::Series)
# first clear out the temporary layer
gplt = getGadflyContext(plt)
if gplt.layers[1].geom.tag == :remove
gplt.layers = gplt.layers[2:end]
end
addGadflySeries!(plt, series.plotattributes)
# push!(plt.seriesargs, plotattributes)
# plt
end
function _update_plot_object(plt::Plot{GadflyBackend}, plotattributes::KW)
updateGadflyGuides(plt, plotattributes)
updateGadflyPlotTheme(plt, plotattributes)
end
# ----------------------------------------------------------------
# accessors for x/y data
# TODO: need to save all the layer indices which apply to this series
function getGadflyMappings(plt::Plot, i::Integer)
@assert i > 0 && i <= plt.n
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
end
function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
# isbefore && return false # wait until after plotting to create the subplots
# subplt.o = nothing
# true
# end
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
# function buildGadflySubplotContext(subplt::Subplot)
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
#
# # add the Plot object to the row
# push!(row, getGadflyContext(subplt.plts[i]))
#
# # add the row
# if c == ncols(subplt.layout, r)
# push!(rows, Gadfly.hstack(row...))
# row = Any[]
# end
# end
#
# # stack the rows
# Gadfly.vstack(rows...)
# end
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
# -------------------------------------------------------------------------
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
func = getGadflyWriteFunc($mime())
doshow(io, func, plt)
end
end
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
setGadflyDisplaySize(plt.attr[:size]...)
display(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
# ctx = buildGadflySubplotContext(subplt)
#
# # taken from Gadfly since I couldn't figure out how to do it directly
#
# filename = string(Gadfly.tempname(), ".html")
# output = open(filename, "w")
#
# plot_output = IOBuffer()
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
# Compose.default_graphic_height, false), ctx)
# plotsvg = takebuf_string(plot_output)
#
# write(output,
# """
# <!DOCTYPE html>
# <html>
# <head>
# <title>Gadfly Plot</title>
# <meta charset="utf-8">
# </head>
# <body>
# <script charset="utf-8">
# $(readall(Compose.snapsvgjs))
# </script>
# <script charset="utf-8">
# $(readall(Gadfly.gadflyjs))
# </script>
# $(plotsvg)
# </body>
# </html>
# """)
# close(output)
# Gadfly.open_file(filename)
# end
-93
View File
@@ -1,93 +0,0 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes
struct ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
new(shape, tag)
end
end
# TODO: add for PR
# const shape = ShapeGeometry
function Gadfly.element_aesthetics(::ShapeGeometry)
[:x, :y, :size, :color]
end
# Generate a form for a shape geometry.
#
# Args:
# geom: shape geometry.
# theme: the plot's theme.
# aes: aesthetics.
#
# Returns:
# A compose Form.
#
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
# TODO: add for PR
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
# element_aesthetics(geom)...)
default_aes = Gadfly.Aesthetics()
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
default_aes.size = Compose.Measure[theme.default_point_size]
aes = Gadfly.inherit(aes, default_aes)
lw_hover_scale = 10
lw_ratio = theme.line_width / aes.size[1]
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
ctx = Compose.compose!(
Compose.context(),
make_polygon(geom, aes.x, aes.y, aes.size),
Compose.fill(aes.color),
Compose.linewidth(theme.highlight_width))
if aes.color_key_continuous != nothing && aes.color_key_continuous
Compose.compose!(ctx,
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
else
Compose.compose!(ctx,
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
for c in aes.color]))
end
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
end
function gadflyshape(sv::Shape)
ShapeGeometry(Any[vertices(sv)])
end
function gadflyshape(sv::AVec{Shape})
ShapeGeometry(Any[vertices(s) for s in sv])
end
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs))
T = Tuple{Compose.Measure, Compose.Measure}
polys = Array(Vector{T}, n)
for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
end
Gadfly.polygon(polys, geom.tag)
end
# ---------------------------------------------------------------------------------------------
-186
View File
@@ -1,186 +0,0 @@
# https://github.com/JuliaGraphics/Immerse.jl
supported_attrs(::ImmerseBackend) = supported_attrs(GadflyBackend())
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
is_subplot_supported(::ImmerseBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::ImmerseBackend; kw...)
@eval begin
import Immerse, Gadfly, Compose, Gtk
export Immerse, Gadfly, Compose, Gtk
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
end
end
function createImmerseFigure(plotattributes::KW)
w,h = plotattributes[:size]
figidx = Immerse.figure(; name = plotattributes[:window_title], width = w, height = h)
Immerse.Figure(figidx)
end
# ----------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::ImmerseBackend, plotattributes::KW)
# # create the underlying Gadfly.Plot object
# gplt = createGadflyPlotObject(plotattributes)
#
# # save both the Immerse.Figure and the Gadfly.Plot
# Plot((nothing,gplt), pkg, 0, plotattributes, KW[])
# end
function _create_backend_figure(plt::Plot{ImmerseBackend})
(nothing, createGadflyPlotObject(plt.attr))
end
# # plot one data series
# function _series_added(::ImmerseBackend, plt::Plot, plotattributes::KW)
# addGadflySeries!(plt, plotattributes)
# push!(plt.seriesargs, plotattributes)
# plt
# end
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
addGadflySeries!(plt, series.plotattributes)
end
function _update_plot_object(plt::Plot{ImmerseBackend}, plotattributes::KW)
updateGadflyGuides(plt, plotattributes)
updateGadflyPlotTheme(plt, plotattributes)
end
# ----------------------------------------------------------------
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
# return false
# # isbefore && return false
# end
#
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
# # create the Gtk window with vertical box vsep
# plotattributes = getattr(subplt,1)
# w,h = plotattributes[:size]
# vsep = Gtk.GtkBoxLeaf(:v)
# win = Gtk.GtkWindowLeaf(vsep, plotattributes[:window_title], w, h)
#
# figindices = []
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# for (i,(r,c)) in enumerate(subplt.layout)
# plt = subplt.plts[i]
#
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
#
# # add the plot's box to the row
# push!(row, box)
#
# # create the figure and store the index returned for destruction later
# figidx = Immerse.figure(canvas)
# push!(figindices, figidx)
#
# fig = Immerse.figure(figidx)
# plt.o = (fig, plt.o[2])
#
# # add the row
# if c == ncols(subplt.layout, r)
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# end
#
# end
#
# # destructor... clean up plots
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
#
# subplt.o = win
# true
# end
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
fig, gplt = plt.o
if fig == nothing
fig = createImmerseFigure(plt.attr)
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
plt.o = (fig, gplt)
end
Immerse.figure(fig.figno; displayfig = false)
display(gplt)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
#
# # if we haven't created the window yet, do it
# if subplt.o == nothing
# showSubplotObject(subplt)
# end
#
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
# for plt in subplt.plts
# fig, gplt = plt.o
# Immerse.figure(fig.figno; displayfig = false)
# display(gplt)
# end
#
# # o is the window... show it
# showall(subplt.o)
# end
-308
View File
@@ -1,308 +0,0 @@
# https://github.com/tbreloff/Qwt.jl
supported_attrs(::QwtBackend) = merge_with_base_supported([
:annotations,
:linecolor,
:fillrange,
:fillcolor,
:label,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:linewidth,
:markershape,
:markercolor,
:markersize,
:bins,
:pos,
:title,
:window_title,
:guide, :lims, :ticks, :scale,
])
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
supported_scales(::QwtBackend) = [:identity, :log10]
is_subplot_supported(::QwtBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::QwtBackend; kw...)
@eval begin
@warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
end
# -------------------------------
const _qwtAliases = KW(
:bins => :heatmap_n,
:fillrange => :fillto,
:linewidth => :width,
:markershape => :marker,
:hexbin => :heatmap,
:path => :line,
:steppost => :step,
:steppre => :stepinverted,
:star5 => :star1,
:star8 => :star2,
)
function fixcolors(plotattributes::KW)
for (k,v) in plotattributes
if typeof(v) <: ColorScheme
plotattributes[k] = getColor(v)
end
end
end
function replaceQwtAliases(plotattributes, s)
if haskey(_qwtAliases, plotattributes[s])
plotattributes[s] = _qwtAliases[plotattributes[s]]
end
end
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
plotattributes = KW(kw)
st = plotattributes[:seriestype]
if st == :scatter
plotattributes[:seriestype] = :none
if plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
elseif st in (:hline, :vline)
addLineMarker(plt, plotattributes)
plotattributes[:seriestype] = :none
plotattributes[:markershape] = :circle
plotattributes[:markersize] = 1
if st == :vline
plotattributes[:x], plotattributes[:y] = plotattributes[:y], plotattributes[:x]
end
elseif !iscreating && st == :bar
plotattributes = barHack(; kw...)
elseif !iscreating && st == :histogram
plotattributes = barHack(; histogramHack(; kw...)...)
end
replaceQwtAliases(plotattributes, :seriestype)
replaceQwtAliases(plotattributes, :markershape)
for k in keys(plotattributes)
if haskey(_qwtAliases, k)
plotattributes[_qwtAliases[k]] = plotattributes[k]
end
end
plotattributes[:x] = collect(plotattributes[:x])
plotattributes[:y] = collect(plotattributes[:y])
plotattributes
end
# function _create_plot(pkg::QwtBackend, plotattributes::KW)
function _create_backend_figure(plt::Plot{QwtBackend})
fixcolors(plt.attr)
dumpdict(plt.attr,"\n\n!!! plot")
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
# plt = Plot(o, pkg, 0, plotattributes, KW[])
# plt
end
# function _series_added(::QwtBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{QwtBackend}, series::Series)
plotattributes = adjustQwtKeywords(plt, false; series.plotattributes...)
fixcolors(plotattributes)
dumpdict(plotattributes,"\n\n!!! plot!")
Qwt.oplot(plt.o; plotattributes...)
# push!(plt.seriesargs, plotattributes)
# plt
end
# ----------------------------------------------------------------
function updateLimsAndTicks(plt::Plot{QwtBackend}, plotattributes::KW, isx::Bool)
lims = get(plotattributes, isx ? :xlims : :ylims, nothing)
ticks = get(plotattributes, isx ? :xticks : :yticks, nothing)
w = plt.o.widget
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
if typeof(lims) <: Union{Tuple,AVec} && length(lims) == 2
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, lims...)
end
if typeof(ticks) <: AbstractRange
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
elseif !(ticks in (nothing, :none, :auto))
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
end
# change the scale
scalesym = isx ? :xscale : :yscale
if haskey(plotattributes, scalesym)
scaletype = plotattributes[scalesym]
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
scaletype in supported_scales() || @warn("Unsupported scale type: ", scaletype)
end
end
function _update_plot_object(plt::Plot{QwtBackend}, plotattributes::KW)
haskey(plotattributes, :title) && Qwt.title(plt.o, plotattributes[:title])
haskey(plotattributes, :xguide) && Qwt.xlabel(plt.o, plotattributes[:xguide])
haskey(plotattributes, :yguide) && Qwt.ylabel(plt.o, plotattributes[:yguide])
updateLimsAndTicks(plt, plotattributes, true)
updateLimsAndTicks(plt, plotattributes, false)
end
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, plotattributes::KW)
haskey(plotattributes, :size) && Qwt.resizewidget(plt.o, plotattributes[:size]...)
haskey(plotattributes, :pos) && Qwt.movewidget(plt.o, plotattributes[:pos]...)
end
# ----------------------------------------------------------------
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
function addLineMarker(plt::Plot{QwtBackend}, plotattributes::KW)
for yi in plotattributes[:y]
marker = Qwt.QWT.QwtPlotMarker()
ishorizontal = (plotattributes[:seriestype] == :hline)
marker[:setLineStyle](ishorizontal ? 1 : 2)
marker[ishorizontal ? :setYValue : :setXValue](yi)
qcolor = Qwt.convertRGBToQColor(getColor(plotattributes[:linecolor]))
linestyle = plt.o.widget[:getLineStyle](string(plotattributes[:linestyle]))
marker[:setLinePen](Qwt.QT.QPen(qcolor, plotattributes[:linewidth], linestyle))
marker[:attach](plt.o.widget)
end
# marker[:setValue](x, y)
# marker[:setLabel](Qwt.QWT.QwtText(val))
# marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
qwttext = Qwt.QWT.QwtText(val.str)
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
marker[:setLabel](qwttext)
marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
marker[:setLabel](Qwt.QWT.QwtText(val))
marker[:attach](plt.o.widget)
end
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createQwtAnnotation(plt, ann...)
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{QwtBackend}, i::Int)
series = plt.o.lines[i]
series.x, series.y
end
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.o.lines[i]
series.x, series.y = xy
plt
end
# -------------------------------
# -------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
# isbefore && return false
# i = 0
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
# push!(row, subplt.plts[i].o)
# if c == ncols(subplt.layout, r)
# push!(rows, Qwt.hsplitter(row...))
# row = Any[]
# end
# end
# # for rowcnt in subplt.layout.rowcounts
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
# # i += rowcnt
# # end
# subplt.o = Qwt.vsplitter(rows...)
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
# true
# end
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
for series in plt.o.lines
_expand_limits(lims, isx ? series.x : series.y)
end
end
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
end
# ----------------------------------------------------------------
function Base.show(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
write(io, readall("/tmp/dfskjdhfkh.png"))
end
# function Base.show(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
# write(io, readall("/tmp/dfskjdhfkh.png"))
# end
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.showwidget(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.showwidget(subplt.o)
# end
-272
View File
@@ -1,272 +0,0 @@
# https://github.com/nolta/Winston.jl
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
supported_attrs(::WinstonBackend) = merge_with_base_supported([
:annotations,
:linecolor,
:fillrange,
:fillcolor,
:label,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:linewidth,
:markershape,
:markercolor,
:markersize,
:bins,
:title,
:window_title,
:guide, :lims, :scale,
])
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::WinstonBackend) = [:identity, :log10]
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.")
import Winston, Gtk
export Winston, Gtk
end
end
# ---------------------------------------------------------------------------
## dictionaries for conversion of Plots.jl names to Winston ones.
const winston_linestyle = KW(:solid=>"solid",
:dash=>"dash",
:dot=>"dotted",
:dashdot=>"dotdashed"
)
const winston_marker = KW(:none=>".",
:rect => "square",
:circle=>"circle",
:diamond=>"diamond",
:utriangle=>"triangle",
:dtriangle=>"down-triangle",
:cross => "plus",
:xcross => "cross",
:star5 => "asterisk"
)
function _before_update(plt::Plot{WinstonBackend})
Winston.ghf(plt.o)
end
# ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{WinstonBackend})
Winston.FramedPlot(
title = plt.attr[:title],
xlabel = plt.attr[:xguide],
ylabel = plt.attr[:yguide]
)
end
copy_remove(plotattributes::KW, s::Symbol) = delete!(copy(plotattributes), s)
function addRegressionLineWinston(plotattributes::KW, wplt)
xs, ys = regressionXY(plotattributes[:x], plotattributes[:y])
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
end
function getWinstonItems(plt::Plot)
if isa(plt.o, Winston.FramedPlot)
wplt = plt.o
window, canvas = nothing, nothing
else
window, canvas, wplt = plt.o
end
window, canvas, wplt
end
function _series_added(plt::Plot{WinstonBackend}, series::Series)
plotattributes = series.plotattributes
window, canvas, wplt = getWinstonItems(plt)
# until we call it normally, do the hack
if plotattributes[:seriestype] == :bar
plotattributes = barHack(;plotattributes...)
end
e = KW()
e[:color] = getColor(plotattributes[:linecolor])
e[:linewidth] = plotattributes[:linewidth]
e[:kind] = winston_linestyle[plotattributes[:linestyle]]
e[:symbolkind] = winston_marker[plotattributes[:markershape]]
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
e[:symbolsize] = plotattributes[:markersize] / 5
# pos # (Int,Int), move the enclosing window to this position
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
if plotattributes[:seriestype] == :none
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
elseif plotattributes[:seriestype] == :path
x, y = plotattributes[:x], plotattributes[:y]
Winston.add(wplt, Winston.Curve(x, y; e...))
fillrange = plotattributes[:fillrange]
if fillrange != nothing
if isa(fillrange, AbstractVector)
y2 = fillrange
else
y2 = Float64[fillrange for yi in y]
end
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(plotattributes[:fillcolor])))
end
elseif plotattributes[:seriestype] == :scatter
if plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
# elseif plotattributes[:seriestype] == :step
# fn = Winston.XXX
# elseif plotattributes[:seriestype] == :stepinverted
# fn = Winston.XXX
elseif plotattributes[:seriestype] == :sticks
Winston.add(wplt, Winston.Stems(plotattributes[:x], plotattributes[:y]; e...))
# elseif plotattributes[:seriestype] == :dots
# fn = Winston.XXX
# elseif plotattributes[:seriestype] == :histogram2d
# fn = Winston.XXX
# elseif plotattributes[:seriestype] == :hexbin
# fn = Winston.XXX
elseif plotattributes[:seriestype] == :histogram
hst = hist(plotattributes[:y], plotattributes[:bins])
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
# elseif plotattributes[:seriestype] == :bar
# # fn = Winston.XXX
else
error("seriestype $(plotattributes[:seriestype]) not supported by Winston.")
end
# markershape
if plotattributes[:markershape] != :none
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
end
# optionally add a regression line
plotattributes[:smooth] && plotattributes[:seriestype] != :histogram && addRegressionLineWinston(plotattributes, wplt)
# push!(plt.seriesargs, plotattributes)
# plt
end
# ----------------------------------------------------------------
const _winstonNames = KW(
:xlims => :xrange,
:ylims => :yrange,
:xscale => :xlog,
:yscale => :ylog,
)
function _update_plot_object(plt::Plot{WinstonBackend}, plotattributes::KW)
window, canvas, wplt = getWinstonItems(plt)
for k in (:xguide, :yguide, :title, :xlims, :ylims)
if haskey(plotattributes, k)
Winston.setattr(wplt, string(get(_winstonNames, k, k)), plotattributes[k])
end
end
for k in (:xscale, :yscale)
if haskey(plotattributes, k)
islogscale = plotattributes[k] == :log10
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
end
end
end
# ----------------------------------------------------------------
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::AbstractString)
Winston.text(x, y, val)
end
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createWinstonAnnotationObject(plt, ann...)
end
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
# end
# ----------------------------------------------------------------
function addWinstonLegend(plt::Plot, wplt)
if plt.attr[:legend] != :none
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
end
end
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
addWinstonLegend(plt, wplt)
show(io, "image/png", wplt)
end
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
if window == nothing
if Winston.output_surface != :gtk
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
end
# initialize window
w,h = plt.attr[:size]
canvas = Gtk.GtkCanvasLeaf()
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
plt.o = (window, canvas, wplt)
end
addWinstonLegend(plt, wplt)
Winston.display(canvas, wplt)
Gtk.showall(window)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
# # TODO: display/show the Subplot object
# end
File diff suppressed because it is too large Load Diff
-415
View File
@@ -1,415 +0,0 @@
abstract type ColorScheme end
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
export
cgrad
cgrad() = default_gradient()
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
colors = ColorGradient(arg, alpha=alpha).colors
values = if values != nothing
values
elseif scale in (:log, :log10)
log10(range(1, stop=10, length=30))
elseif scale == :log2
log2(range(1, stop=2, length=30))
elseif scale == :ln
log(range(1, stop=pi, length=30))
elseif scale in (:exp, :exp10)
(exp10(range(0, stop=1, length=30)) - 1) / 9
else
range(0, stop=1, length=length(colors))
end
ColorGradient(colors, values)
end
# --------------------------------------------------------------
getColor(scheme::ColorScheme) = getColor(scheme, 1)
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
# --------------------------------------------------------------
convertColor(c::AbstractString) = parse(Colorant, c)
convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
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)
c = convertColor(c)
RGBA(RGB(getColor(c)), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::Nothing) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
# --------------------------------------------------------------
function darken(c, v=0.1)
rgba = convert(RGBA, c)
r = max(0, min(rgba.r - v, 1))
g = max(0, min(rgba.g - v, 1))
b = max(0, min(rgba.b - v, 1))
RGBA(r,g,b,rgba.alpha)
end
function lighten(c, v=0.3)
darken(c, -v)
end
# --------------------------------------------------------------
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
const _gradients = KW(
:blues => [colorant"lightblue", colorant"darkblue"],
:reds => [colorant"lightpink", colorant"darkred"],
:greens => [colorant"lightgreen", colorant"darkgreen"],
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
:rainbow => _rainbowColors,
:lightrainbow => map(lighten, _rainbowColors),
:darkrainbow => map(darken, _rainbowColors),
:darktest => _testColors,
:lighttest => map(c -> lighten(c, 0.3), _testColors),
)
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
_gradients[name] = colors
end
include("color_gradients.jl")
default_gradient() = ColorGradient(:inferno)
# --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
struct ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient(cs::AVec, vals::AVec{S} = range(0, stop=1, length=length(cs)); alpha = nothing) where S<:Real
if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals))
end
# # otherwise interpolate evenly between the minval and maxval
# minval, maxval = minimum(vals), maximum(vals)
# vs = Float64[interpolate(minval, maxval, w) for w in range(0, stop = 1, length = length(cs))]
# new(convertColor(cs,alpha), vs)
# interpolate the colors for each value
vals = merge(range(0, stop=1, length=length(cs)), vals)
grad = ColorGradient(cs)
cs = [getColorZ(grad, z) for z in range(0, stop=1, length=length(vals))]
new(convertColor(cs, alpha), vals)
end
end
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient(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 = range(0, stop=1, length=length(cs))
end
ColorGradient(cs, vals; kw...)
end
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
# ColorGradient(map(convertColor, cs), vals; kw...)
# end
function ColorGradient(grad::ColorGradient; alpha = nothing)
ColorGradient(convertColor(grad.colors, alpha), grad.values)
end
# anything else just gets the default gradient
function ColorGradient(cw; alpha=nothing)
ColorGradient(default_gradient(), alpha=alpha)
end
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
function getColorZ(gradient::ColorGradient, z::Real)
cs = gradient.colors
vs = gradient.values
n = length(cs)
@assert n > 0 && n == length(vs)
# can we just return the first color?
if z <= vs[1] || n == 1
return cs[1]
end
# find the bounding colors and interpolate
for i in 2:n
if z <= vs[i]
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
end
end
# if we get here, return the last color
cs[end]
end
getColorVector(gradient::ColorGradient) = gradient.colors
# for 0.3
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
rgb1 = RGBA(c1)
rgb2 = RGBA(c2)
r = interpolate(rgb1.r, rgb2.r, w)
g = interpolate(rgb1.g, rgb2.g, w)
b = interpolate(rgb1.b, rgb2.b, w)
a = interpolate(rgb1.alpha, rgb2.alpha, w)
RGBA(r, g, b, a)
end
function interpolate(v1::Real, v2::Real, w::Real)
(1-w) * v1 + w * v2
end
# --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant"
struct ColorFunction <: ColorScheme
f::Function
end
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant"
struct ColorZFunction <: ColorScheme
f::Function
end
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
struct ColorVector <: ColorScheme
v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
getColorVector(scheme::ColorVector) = scheme.v
# --------------------------------------------------------------
"Wraps a single color"
struct ColorWrapper <: ColorScheme
c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
end
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
convertColor(c::ColorWrapper, α::Nothing) = c.c
# --------------------------------------------------------------
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
# move closer to lighter/darker depending on background value
function adjustAway(val, bgval, vmin=0., vmax=100.)
if bgval < 0.5 * (vmax+vmin)
tmp = max(val, bgval)
return 0.5 * (tmp + max(tmp, vmax))
else
tmp = min(val, bgval)
return 0.5 * (tmp + min(tmp, vmin))
end
end
# borrowed from http://stackoverflow.com/a/1855903:
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
isdark(c::Colorant) = lightnessLevel(c) < 0.5
islight(c::Colorant) = !isdark(c)
function convertHexToRGB(h::Unsigned)
mask = 0x0000FF
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
end
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
const _masterColorList = [
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
]
const _allColors = map(convertHexToRGB, _masterColorList)
const _darkColors = filter(isdark, _allColors)
const _lightColors = filter(islight, _allColors)
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
const _defaultNumColors = 17
# --------------------------------------------------------------
# Methods to automatically generate gradients for color selection based on
# background color and a short list of seed colors
# here are some magic constants that could be changed if you really want
const _lightness_darkbg = [80.0]
const _lightness_lightbg = [60.0]
const _lch_c_const = [60]
function adjust_lch(color, l, c)
lch = convert(LCHab, color)
convert(RGB, LCHab(l, c, lch.h))
end
function lightness_from_background(bgcolor)
bglight = convert(LCHab, bgcolor).l
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
end
function gradient_from_list(cs)
zvalues = Plots.get_zvalues(length(cs))
indices = sortperm(zvalues)
sorted_colors = map(RGBA, cs[indices])
sorted_zvalues = zvalues[indices]
ColorGradient(sorted_colors, sorted_zvalues)
end
function generate_colorgradient(bgcolor = colorant"white";
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
lightness = lightness_from_background(bgcolor),
chroma = _lch_c_const[1],
n = _defaultNumColors)
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
colors = distinguishable_colors(n,
seed_colors,
lchoices=Float64[lightness],
cchoices=Float64[chroma],
hchoices=range(0, stop=340, length=20)
)[2:end]
gradient_from_list(colors)
end
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
grad = if palette == :auto
generate_colorgradient(bgcolor)
else
ColorGradient(palette)
end
zrng = get_zvalues(numcolors)
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
palette
end
# ----------------------------------------------------------------------------------
function getpctrange(n::Int)
n > 0 || error()
n == 1 && return zeros(1)
zs = [0.0, 1.0]
for i in 3:n
sorted = sort(zs)
diffs = diff(sorted)
widestj = 0
widest = 0.0
for (j,d) in enumerate(diffs)
if d > widest
widest = d
widestj = j
end
end
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
end
zs
end
function get_zvalues(n::Int)
offsets = getpctrange(ceil(Int,n/4)+1)/4
offsets = vcat(offsets[1], offsets[3:end])
zvalues = Float64[]
for offset in offsets
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
end
vcat(zvalues[1], 1.0, zvalues[2:n-1])
end
# ----------------------------------------------------------------------------------
make255(x) = round(Int, 255 * x)
function webcolor(c::Color)
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
end
function webcolor(c::TransparentColor)
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
end
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
webcolor(c) = webcolor(convertColor(c))
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
# ----------------------------------------------------------------------------------
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, sp::Subplot, n::Int)
if c == :auto
c = autopick(sp[:color_palette], n)
end
# c should now be a subtype of ColorScheme
colorscheme(c)
end
-63
View File
@@ -1,63 +0,0 @@
# TODO:
"""
- load Contours.jl similar to DataFrames
- method to build grid from x/y/z vectors
- method to wrap contours creation
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
"""
# # ----------------------------------------------------------
# # ----------------------------------------------------------
# immutable Vertex
# x::Float64
# y::Float64
# z::Float64
# end
# immutable Edge
# v::Vertex
# u::Vertex
# end
# # ----------------------------------------------------------
# # one rectangle's z-values and the center vertex
# # z is ordered: topleft, topright, bottomright, bottomleft
# immutable GridRect
# z::Vector{Float64}
# center::Vertex
# data::Vector{Vertex}
# end
# type Grid
# xs::Vector{Float64}
# ys::Vector{Float64}
# rects::Matrix{GridRect}
# end
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
# vs = sort(v)
# end
# # the goal here is to create the vertical and horizontal partitions
# # which define the grid, so that the data is somewhat evenly split
# function bucketData(x, y, z)
# end
# function buildGrid(x, y, z)
# # create
# end
-99
View File
@@ -1,99 +0,0 @@
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
# Then once inputs have been converted, build the series args, map functions, etc.
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
const FuncOrFuncs = Union{Function, AVec{Function}}
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(plotattributes, :seriestype, :none))
# missing
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, plotattributes::KW)
if all3D(plotattributes)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# function
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
# dates
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, plotattributes::KW)
if all(x -> typeof(x) <: Number, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
function convertToAnyVector(args...)
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
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::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::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::Nothing) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
nobigs(v::AVec{BigInt}) = map(Int64, v)
nobigs(v) = v
@noinline function compute_xyz(x, y, z)
x = compute_x(x,y,z)
y = compute_y(x,y,z)
z = compute_z(x,y,z)
nobigs(x), nobigs(y), nobigs(z)
end
# not allowed
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!")
# --------------------------------------------------------------------
+33 -3
View File
@@ -86,8 +86,9 @@ yaxis!("YLABEL", :log10)
PlotExample("Images",
"Plot an image. y-axis is set to flipped",
[:(begin
import FileIO, PlotReferenceImages
img = FileIO.load(joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots","pyplot","0.7.0","ref1.png"))
import FileIO
path = download("http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png")
img = FileIO.load(path)
plot(img)
end)]
),
@@ -435,8 +436,37 @@ each line segment or marker in the plot.
end)]
),
PlotExample("Portfolio Composition maps",
"""
see: http://stackoverflow.com/a/37732384/5075246
""",
[:(begin
using Random
Random.seed!(111)
tickers = ["IBM", "Google", "Apple", "Intel"]
N = 10
D = length(tickers)
weights = rand(N,D)
weights ./= sum(weights, dims = 2)
returns = sort!((1:N) + D*randn(N))
portfoliocomposition(weights, returns, labels = permutedims(tickers))
end)]
),
]
# Some constants for PlotDocs and PlotReferenceImages
_animation_examples = [2, 30]
_backend_skips = Dict(
:gr => [25, 30],
:pyplot => [25, 30],
:plotlyjs => [2, 21, 25, 30, 31],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30],
)
# ---------------------------------------------------------------------------------
# make and display one plot
@@ -473,7 +503,7 @@ function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = noth
plts[i] = plt
catch ex
# TODO: put error info into markdown?
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
@warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
end
if sleep != nothing
Base.sleep(sleep)
+24
View File
@@ -0,0 +1,24 @@
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString)
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x)
function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = _fileio_load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
_fileio_save(pngfn, s)
# now write from the file
write(io, read(open(pngfn), String))
end
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
+59
View File
@@ -0,0 +1,59 @@
const use_local_dependencies = Ref(false)
const use_local_plotlyjs = Ref(false)
function _init_ijulia_plotting()
# IJulia is more stable with local file
use_local_plotlyjs[] = isfile(plotly_local_file_path)
ENV["MPLBACKEND"] = "Agg"
end
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out
function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
out
end
function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function _ijulia_display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
_ijulia__extra_mime_info!(plt, out)
out
end
+39 -66
View File
@@ -1,26 +1,33 @@
function __init__()
using REPL
function _plots_defaults()
if isdefined(Main, :PLOTS_DEFAULTS)
if haskey(Main.PLOTS_DEFAULTS, :theme)
theme(Main.PLOTS_DEFAULTS[:theme])
end
for (k,v) in Main.PLOTS_DEFAULTS
k == :theme || default(k, v)
end
Dict{Symbol,Any}(Main.PLOTS_DEFAULTS)
else
Dict{Symbol,Any}()
end
pushdisplay(PlotsDisplay())
end
function __init__()
user_defaults = _plots_defaults()
if haskey(user_defaults, :theme)
theme(user_defaults[:theme])
end
for (k,v) in user_defaults
k == :theme || default(k, v)
end
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
atreplinit(i -> begin
if PlotDisplay() in Base.Multimedia.displays
while PlotsDisplay() in Base.Multimedia.displays
popdisplay(PlotsDisplay())
end
pushdisplay(PlotsDisplay())
insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
end)
include(joinpath(@__DIR__, "backends", "plotly.jl"))
include(joinpath(@__DIR__, "backends", "gr.jl"))
include(joinpath(@__DIR__, "backends", "web.jl"))
@require GLVisualize = "4086de5b-f4b6-55f3-abb0-b8c73827585f" include(joinpath(@__DIR__, "backends", "glvisualize.jl"))
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
@@ -28,60 +35,26 @@ function __init__()
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl"))
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl"))
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
if IJulia.inited
_init_ijulia_plotting()
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_extra_mime_info!(plt::Plot, out::Dict) = out
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
out
end
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function IJulia.display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
_extra_mime_info!(plt, out)
out
end
ENV["MPLBACKEND"] = "Agg"
IJulia.display_dict(plt::Plot) = _ijulia_display_dict(plt)
end
end
if haskey(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL")
use_local_plotlyjs[] = ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] == "true"
use_local_dependencies[] = isfile(plotly_local_file_path) && use_local_plotlyjs[]
if use_local_plotlyjs[] && !isfile(plotly_local_file_path)
@warn("PLOTS_HOST_DEPENDENCY_LOCAL is set to true, but no local plotly file found. run Pkg.build(\"Plots\") and make sure PLOTS_HOST_DEPENDENCY_LOCAL is set to true")
end
else
use_local_dependencies[] = use_local_plotlyjs[]
end
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt)
end
end
+1 -1
View File
@@ -111,7 +111,7 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
pct += mix.len / totlen
end
if pct != 0
amin, amax = axis_limits(sp[Symbol(letter,:axis)])
amin, amax = axis_limits(sp, letter)
xy += pct * (amax-amin)
end
xy
+19 -33
View File
@@ -55,9 +55,7 @@ tex(fn::AbstractString) = tex(current(), fn)
function html(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "html")
io = open(fn, "w")
_use_remote[] = true
show(io, MIME("text/html"), plt)
_use_remote[] = false
close(io)
end
html(fn::AbstractString) = html(current(), fn)
@@ -156,7 +154,6 @@ end
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
:glvisualize => :png,
:plotlyjs => :html,
:plotly => :html
)
@@ -192,7 +189,7 @@ end
# for writing to io streams... first prepare, then callback
for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml",
"application/eps", "application/pdf", "application/postscript",
"application/x-tex")
"application/x-tex", "application/vnd.plotly.v1+json")
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
if haskey(io, :juno_plotsize)
showjuno(io, m, plt)
@@ -200,6 +197,7 @@ for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml
prepare_output(plt)
_show(io, m, plt)
end
return nothing
end
end
@@ -210,30 +208,6 @@ _show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
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{<:PDFBackends})
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = FileIO.load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
FileIO.save(pngfn, s)
# now write from the file
write(io, read(open(pngfn), String))
end
end
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
@@ -267,9 +241,21 @@ function showjuno(io::IO, m, plt)
plt[:thickness_scaling] *= scale
prepare_output(plt)
_show(io, m, plt)
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
try
_showjuno(io, m, plt)
finally
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end
end
function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
if Symbol(plt.attr[:html_output_format]) :svg
throw(MethodError(show, (typeof(m), typeof(plt))))
else
_show(io, m, plt)
end
end
_showjuno(io::IO, m, plt) = _show(io, m, plt)
+2 -2
View File
@@ -166,9 +166,9 @@ end
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
plotattributes[:plot_object] = plt
if !isempty(args) && !isdefined(Main, :StatPlots) &&
if !isempty(args) && !isdefined(Main, :StatsPlots) &&
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 StatsPlots")
end
# --------------------------------
+8 -3
View File
@@ -18,7 +18,7 @@ end
plotattr([attr])
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
The information is the same as that given on https://juliaplots.github.io/attributes/.
The information is the same as that given on https://docs.juliaplots.org/latest/attributes/.
"""
function plotattr()
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
@@ -50,8 +50,13 @@ function plotattr(attrtype::Symbol, attribute::AbstractString)
desc = get(_arg_desc, attribute, "")
first_period_idx = findfirst(isequal('.'), desc)
typedesc = desc[1:first_period_idx-1]
desc = strip(desc[first_period_idx+1:end])
if isnothing(first_period_idx)
typedesc = ""
desc = strip(desc)
else
typedesc = desc[1:first_period_idx-1]
desc = strip(desc[first_period_idx+1:end])
end
als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort
als = join(map(string,als), ", ")
def = _attribute_defaults[attrtype][attribute]
+117 -43
View File
@@ -47,16 +47,47 @@ end
num_series(x::AMat) = size(x,2)
num_series(x) = 1
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
# for seriestype `line`, need to sort by x values
const POTENTIAL_VECTOR_ARGUMENTS = [
:seriescolor, :seriesalpha,
:linecolor, :linealpha, :linewidth, :linestyle, :line_z,
:fillcolor, :fillalpha, :fill_z,
:markercolor, :markeralpha, :markershape, :marker_z,
:markerstrokecolor, :markerstrokealpha,
:yerror, :yerror,
:series_annotations, :fillrange
]
@recipe function f(::Type{Val{:line}}, x, y, z)
indices = sortperm(x)
x := x[indices]
y := y[indices]
# sort vector arguments
for arg in POTENTIAL_VECTOR_ARGUMENTS
if typeof(plotattributes[arg]) <: AVec
plotattributes[arg] = _cycle(plotattributes[arg], indices)
end
end
# a tuple as fillrange has to be handled differently
if typeof(plotattributes[:fillrange]) <: Tuple
lower, upper = plotattributes[:fillrange]
if typeof(lower) <: AVec
lower = _cycle(lower, indices)
end
if typeof(upper) <: AVec
upper = _cycle(upper, indices)
end
plotattributes[:fillrange] = (lower, upper)
end
if typeof(z) <: AVec
z := z[indices]
end
@@ -65,19 +96,6 @@ RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where
end
@deps line path
function hvline_limits(axis::Axis)
vmin, vmax = axis_limits(axis)
if vmin >= vmax
if isfinite(vmin)
vmax = vmin + 1
else
vmin, vmax = 0.0, 1.1
end
end
vmin, vmax
end
@recipe function f(::Type{Val{:hline}}, x, y, z)
n = length(y)
newx = repeat(Float64[-1, 1, NaN], n)
@@ -222,11 +240,12 @@ end
n = length(x)
fr = plotattributes[:fillrange]
if fr == nothing
yaxis = plotattributes[:subplot][:yaxis]
sp = plotattributes[:subplot]
yaxis = sp[:yaxis]
fr = if yaxis[:scale] == :identity
0.0
else
NaNMath.min(axis_limits(yaxis)[1], ignorenan_minimum(y))
NaNMath.min(axis_limits(sp, :y)[1], ignorenan_minimum(y))
end
end
newx, newy = zeros(3n), zeros(3n)
@@ -519,13 +538,15 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
w, it_state_w = it_tuple_w
if (log_scale_x && a 0)
a = b/_logScaleBases[xscale]^3
a = oftype(a, b/_logScaleBases[xscale]^3)
end
if isnan(w)
if !isnan(last_w)
push!(x, a)
push!(y, baseline)
push!(x, NaN)
push!(y, NaN)
end
else
if isnan(last_w)
@@ -538,8 +559,8 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
push!(y, w)
end
a = b
last_w = w
a = oftype(a, b)
last_w = oftype(last_w, w)
it_tuple_e = iterate(edge, it_state_e)
it_tuple_w = iterate(weights, it_state_w)
@@ -586,12 +607,13 @@ end
end
Plots.@deps stepbins path
wand_edges(x...) = (@warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
wand_edges(x...) = (@warn("Load the StatsPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
max_bins = 10_000
_cl(x) = min(ceil(Int, max(x, one(x))), max_bins)
_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)
_span(v) = maximum(v) - minimum(v)
n_samples = length(LinearIndices(first(vs)))
@@ -616,7 +638,7 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
elseif mode == :fd # FreedmanDiaconis rule
_cl(_span(v) / (2 * _iqr(v) / nd))
elseif mode == :wand
wand_edges(v) # this makes this function not type stable, but the type instability does not propagate
_cl(wand_edges(v)) # this makes this function not type stable, but the type instability does not propagate
else
error("Unknown auto-binning mode $mode")
end
@@ -635,11 +657,19 @@ _hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, Abstra
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
_filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs)
function _filternans(vs::NTuple{N,AbstractVector}) where N
_invertedindex(v, not) = [j for (i,j) in enumerate(v) if !(i not)]
nots = union(Set.(findall.(!isfinite, vs))...)
_invertedindex.(vs, Ref(nots))
end
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
edges = _hist_edges(vs, binning)
localvs = _filternans(vs)
edges = _hist_edges(localvs, binning)
h = float( weights == nothing ?
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, vs, StatsBase.Weights(weights), edges, closed = :left)
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, localvs, StatsBase.Weights(weights), edges, closed = :left)
)
normalize!(h, mode = _hist_norm_mode(normed))
end
@@ -1024,10 +1054,6 @@ end
@assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix
seriestype := :spy
mat = g.args[1]
if length(unique(mat[mat .!= 0])) < 2
legend --> nothing
seriescolor --> cgrad([invisible(), fg_color(plotattributes)])
end
n,m = size(mat)
Plots.SliceIt, 1:m, 1:n, Surface(mat)
end
@@ -1035,27 +1061,29 @@ end
@recipe function f(::Type{Val{:spy}}, x,y,z)
yflip := true
aspect_ratio := 1
rs, cs, zs = findnz(z.surf)
newz = fill(NaN, size(z)...)
for i in eachindex(zs)
newz[rs[i],cs[i]] = zs[i]
xlim := ignorenan_extrema(cs)
ylim := ignorenan_extrema(rs)
if plotattributes[:markershape] == :none
markershape := :circle
end
seriestype := :heatmap
if plotattributes[:markersize] == default(:markersize)
markersize := 1
end
markerstrokewidth := 0
marker_z := zs
label := ""
x := cs
y := rs
z := nothing
seriestype := :scatter
grid --> false
framestyle --> :box
x := x
y := y
z := Surface(newz)
()
end
# -------------------------------------------------
"Adds a+bx... straight line over the current plot, without changing the axis limits"
"Adds ax+b... straight line over the current plot, without changing the axis limits"
abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...)
abline!(args...; kw...) = abline!(current(), args...; kw...)
@@ -1133,3 +1161,49 @@ end
title := string(grad.args[1])
z
end
# Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246
@userplot PortfolioComposition
# this shows the shifting composition of a basket of something over a variable
# - "returns" are the dependent variable
# - "weights" are a matrix where the ith column is the composition for returns[i]
# - since each polygon is its own series, you can assign labels easily
@recipe function f(pc::PortfolioComposition)
weights, returns = pc.args
n = length(returns)
weights = cumsum(weights, dims = 2)
seriestype := :shape
# create a filled polygon for each item
for c=1:size(weights,2)
sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1]))
sy = vcat(returns, reverse(returns))
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
end
end
"""
areaplot([x,] y)
areaplot!([x,] y)
Draw a stacked area plot of the matrix y.
# Examples
```julia-repl
julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], fillalpha = [0.2 0.3 0.4])
```
"""
@userplot AreaPlot
@recipe function f(a::AreaPlot)
data = cumsum(a.args[end], dims=2)
x = length(a.args) == 1 ? (1:size(data, 1)) : a.args[1]
seriestype := :line
for i in 1:size(data, 2)
@series begin
fillrange := i > 1 ? data[:,i-1] : 0
x, data[:,i]
end
end
end
+39 -40
View File
@@ -19,13 +19,11 @@ convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
# numeric/string vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Union{Number,String,Missing}} = Any[handlemissings(v)], nothing
function convertToAnyVector(v::AMat, plotattributes::KW)
v = handlemissings(v)
if all3D(plotattributes)
Any[Surface(v)]
else
@@ -33,6 +31,10 @@ function convertToAnyVector(v::AMat, plotattributes::KW)
end, nothing
end
handlemissings(v) = v
handlemissings(v::AbstractArray{Union{T,Missing}}) where T <: Number = replace(v, missing => NaN)
handlemissings(v::AbstractArray{Union{T,Missing}}) where T <: String = replace(v, missing => "")
# function
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
@@ -186,8 +188,9 @@ _apply_type_recipe(plotattributes, v) = RecipesBase.apply_recipe(plotattributes,
# This sort of recipe should return a pair of functions... one to convert to number,
# and one to format tick values.
function _apply_type_recipe(plotattributes, v::AbstractArray)
isempty(v) && return Float64[]
args = RecipesBase.apply_recipe(plotattributes, typeof(v[1]), v[1])[1].args
isempty(skipmissing(v)) && return Float64[]
x = first(skipmissing(v))
args = RecipesBase.apply_recipe(plotattributes, typeof(x), x)[1].args
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
numfunc, formatter = args
Formatted(map(numfunc, v), formatter)
@@ -316,19 +319,26 @@ end
# # images - grays
function clamp_greys!(mat::AMat{T}) where T<:Gray
for i in eachindex(mat)
mat[i].val < 0 && (mat[i] = Gray(0))
mat[i].val > 1 && (mat[i] = Gray(1))
end
mat
end
@recipe function f(mat::AMat{T}) where T<:Gray
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
SliceIt, 1:m, 1:n, Surface(clamp_greys!(mat))
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
SliceIt, 1:m, 1:n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.))
end
end
@@ -377,10 +387,11 @@ end
@recipe function f(f::FuncOrFuncs{F}) where F<:Function
plt = plotattributes[:plot_object]
xmin, xmax = try
axis_limits(plt[1][:xaxis])
axis_limits(plt[1], :x)
catch
xm = tryrange(f, [-5,-1,0,0.01])
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
xinv = invscalefunc(get(plotattributes, :xscale, :identity))
xm = tryrange(f, xinv.([-5,-1,0,0.01]))
xm, tryrange(f, filter(x->x>xm, xinv.([5,1,0.99, 0, -0.01])))
end
f, xmin, xmax
@@ -510,16 +521,23 @@ end
#
# # special handling... xmin/xmax with parametric function(s)
@recipe function f(f::Function, xmin::Number, xmax::Number)
xs = adapted_grid(f, (xmin, xmax))
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
xs = _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
xs, f
end
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
xs = Any[_scaled_adapted_grid(f, xscale, yscale, xmin, xmax) for f in fs]
xs, fs
end
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n)
function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
(xf, xinv), (yf, yinv) = ((scalefunc(s),invscalefunc(s)) for s in (xscale,yscale))
xinv.(adapted_grid(yf∘f∘xinv, xf.((xmin, xmax))))
end
#
# # special handling... 3D parametric function(s)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
@@ -532,36 +550,17 @@ end
#
#
# # --------------------------------------------------------------------
# # Lists of tuples and FixedSizeArrays
# # Lists of tuples and GeometryTypes.Points
# # --------------------------------------------------------------------
#
# # if we get an unhandled tuple, just splat it in
@recipe f(tup::Tuple) = tup
#
# # (x,y) tuples
@recipe f(xy::AVec{Tuple{R1,R2}}) where {R1<:Number,R2<:Number} = unzip(xy)
@recipe f(xy::Tuple{R1,R2}) where {R1<:Number,R2<:Number} = [xy[1]], [xy[2]]
@recipe f(v::AVec{<:Tuple}) = unzip(v)
@recipe f(v::AVec{<:GeometryTypes.Point}) = unzip(v)
@recipe f(tup::Tuple) = [tup]
@recipe f(p::GeometryTypes.Point) = [p]
#
# # (x,y,z) tuples
@recipe f(xyz::AVec{Tuple{R1,R2,R3}}) where {R1<:Number,R2<:Number,R3<:Number} = unzip(xyz)
@recipe f(xyz::Tuple{R1,R2,R3}) where {R1<:Number,R2<:Number,R3<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else
@recipe f(xyuv::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f(xyuv::Tuple{R1,R2,R3,R4}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
#
# # 2D FixedSizeArrays
@recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
@recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
#
# # 3D FixedSizeArrays
@recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
@recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# Special case for 4-tuples in :ohlc series
@recipe f(xyuv::AVec{<:Tuple{R1,R2,R3,R4}}) where {R1,R2,R3,R4} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
#
# # --------------------------------------------------------------------
+455
View File
@@ -0,0 +1,455 @@
"""
scatter(x,y)
scatter!(x,y)
Make a scatter plot of y vs x.
# Examples
```julia-repl
julia> scatter([1,2,3],[4,5,6],markersize=[3,4,5],markercolor=[:red,:green,:blue])
julia> scatter([(1,4),(2,5),(3,6)])
```
"""
@shorthands scatter
"""
bar(x,y)
bar!(x,y)
Make a bar plot of y vs x.
# Arguments
- $(_document_argument("bar_position"))
- $(_document_argument("bar_width"))
- $(_document_argument("bar_edges"))
- $(_document_argument("orientation"))
# Examples
```julia-repl
julia> bar([1,2,3],[4,5,6],fillcolor=[:red,:green,:blue],fillalpha=[0.2,0.4,0.6])
julia> bar([(1,4),(2,5),(3,6)])
```
"""
@shorthands bar
@shorthands barh
"""
histogram(x)
histogram!(x)
Plot a histogram.
# Arguments
- `x`: AbstractVector of values to be binned
- $(_document_argument("bins"))
- `weights`: Vector of weights for the values in `x`, for weighted bin counts
- $(_document_argument("normalize"))
- $(_document_argument("bar_position"))
- $(_document_argument("bar_width"))
- $(_document_argument("bar_edges"))
- $(_document_argument("orientation"))
# Example
```julia-repl
julia> histogram([1,2,1,1,4,3,8],bins=0:8)
```
"""
@shorthands histogram
"""
barhist(x)
barhist!(x)
Make a histogram bar plot. See `histogram`.
"""
@shorthands barhist
"""
stephist(x)
stephist(x)
Make a histogram step plot (bin counts are represented using horizontal lines
instead of bars). See `histogram`.
"""
@shorthands stephist
"""
scatterhist(x)
scatterhist!(x)
Make a histogram scatter plot (bin counts are represented using points
instead of bars). See `histogram`.
"""
@shorthands scatterhist
"""
histogram2d(x,y)
histogram2d!(x,y)
Plot a two-dimensional histogram.
# Arguments
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
its weight to the height of its bin.
# Example
```julia-repl
julia> histogram2d(randn(10_000),randn(10_000))
```
"""
@shorthands histogram2d
"""
density(x)
density!(x)
Make a line plot of a kernel density estimate of x.
# Arguments
- `x`: AbstractVector of samples for probability density estimation
# Example
```julia-repl
julia> using StatsPlots
julia> density(randn(100_000))
```
"""
@shorthands density
"""
heatmap(x,y,z)
heatmap!(x,y,z)
Plot a heatmap of the rectangular array `z`.
# Example
```julia-repl
julia> heatmap(randn(10,10))
```
"""
@shorthands heatmap
@shorthands plots_heatmap
"""
hexbin(x,y)
hexbin!(x,y)
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
with hexagonal bins)
# Example
```julia-repl
julia> hexbin(randn(10_000), randn(10_000))
```
"""
@shorthands hexbin
"""
sticks(x,y)
sticks!(x,y)
Draw a stick plot of y vs x.
# Example
```julia-repl
julia> sticks(1:10)
```
"""
@shorthands sticks
"""
hline(y)
hline!(y)
Draw horizontal lines at positions specified by the values in
the AbstractVector `y`
# Example
```julia-repl
julia> hline([-1,0,2])
```
"""
@shorthands hline
"""
vline(x)
vline!(x)
Draw vertical lines at positions specified by the values in
the AbstractVector `x`
# Example
```julia-repl
julia> vline([-1,0,2])
```
"""
@shorthands vline
"""
hspan(y)
Draw a rectangle between the horizontal line at position `y[1]`
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
then further rectangles are drawn between `y[3]` and `y[4]`,
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
last entry of `y` is ignored.
# Example
```julia-repl
julia> hspan(1:6)
```
"""
@shorthands hspan
"""
vspan(x)
Draw a rectangle between the vertical line at position `x[1]`
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
then further rectangles are drawn between `x[3]` and `x[4]`,
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
last entry of `x` is ignored.
# Example
```julia-repl
julia> vspan(1:6)
```
"""
@shorthands vspan
"""
ohlc(x,y::Vector{OHLC})
ohlc!(x,y::Vector{OHLC})
Make open-high-low-close plot. Each entry of y is represented by a vertical
segment extending from the low value to the high value, with short horizontal
segments on the left and right indicating the open and close values, respectively.
# Example
```julia-repl
julia> meanprices = cumsum(randn(100))
julia> y = OHLC[(p+rand(),p+1,p-1,p+rand()) for p in meanprices]
julia> ohlc(y)
```
"""
@shorthands ohlc
"""
contour(x,y,z)
contour!(x,y,z)
Draw contour lines of the `Surface` z.
# Arguments
- `levels`: Contour levels (if `AbstractVector`) or number of levels (if `Integer`)
- `fill`: Bool. Fill area between contours or draw contours only (false by default)
# Example
```julia-repl
julia> x = y = range(-20, 20, length = 100)
julia> contour(x, y, (x, y) -> x^2 + y^2)
```
"""
@shorthands contour
"An alias for `contour` with fill = true."
@shorthands contourf
@shorthands contour3d
"""
surface(x,y,z)
surface!(x,y,z)
Draw a 3D surface plot.
# Example
```julia-repl
julia> x = y = range(-3, 3, length = 100)
julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
```
"""
@shorthands surface
"""
wireframe(x,y,z)
wireframe!(x,y,z)
Draw a 3D wireframe plot.
# Example
```julia-repl
julia> wireframe(1:10,1:10,randn(10,10))
```
"""
@shorthands wireframe
"""
path3d(x,y,z)
path3d!(x,y,z)
Plot a 3D path from `(x[1],y[1],z[1])` to `(x[2],y[2],z[2])`,
..., to `(x[end],y[end],z[end])`.
# Example
```julia-repl
julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
```
"""
@shorthands path3d
"""
scatter3d(x,y,z)
scatter3d!(x,y,z)
Make a 3D scatter plot.
# Example
```julia-repl
julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
```
"""
@shorthands scatter3d
"""
boxplot(x, y)
boxplot!(x, y)
Make a box and whisker plot.
# Keyword arguments
- `notch`: Bool. Notch the box plot? (false)
- `range`: Real. Values more than range*IQR below the first quartile
or above the third quartile are shown as outliers (1.5)
- `outliers`: Bool. Show outliers? (true)
- `whisker_width`: Real or Symbol. Length of whiskers (:match)
# Example
```julia-repl
julia> using StatsPlots
julia> boxplot(repeat([1,2,3],outer=100),randn(300))
```
"""
@shorthands boxplot
"""
violin(x,y,z)
violin!(x,y,z)
Make a violin plot.
# Example
```julia-repl
julia> violin(repeat([1,2,3],outer=100),randn(300))
```
"""
@shorthands violin
"""
quiver(x,y,quiver=(u,v))
quiver!(x,y,quiver=(u,v))
Make a quiver (vector field) plot. The `i`th vector extends
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
# Example
```julia-repl
julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
```
"""
@shorthands quiver
"""
curves(x,y)
curves!(x,y)
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
with control points `(x[2],y[2]), ..., (x[end-1],y[end]-1)`
# Example
```julia-repl
julia> curves([1,2,3,4],[1,1,2,4])
```
"""
@shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"""
annotate!(anns...)
Add annotations to an existing plot.
# Arguments
- `anns`: An `AbstractVector` of tuples of the form (x,y,text). The text object
can be an String or PlotText
# Example
```julia-repl
julia> plot(1:10)
julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))])
```
"""
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify y axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
+1 -1
View File
@@ -100,7 +100,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
end
end
srand(1)
Random.seed!(1)
label := ""
colorbar := false
+117 -109
View File
@@ -194,7 +194,9 @@ end
function iter_segments(series::Series)
x, y, z = series[:x], series[:y], series[:z]
if has_attribute_segments(series)
if x == nothing
return UnitRange{Int}[]
elseif has_attribute_segments(series)
if series[:seriestype] in (:scatter, :scatter3d)
return [[i] for i in 1:length(y)]
else
@@ -212,36 +214,19 @@ end
# helpers to figure out if there are NaN values in a list of array types
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)
anynan(args::Tuple) = i -> anynan(i,args)
anynan(istart::Int, iend::Int, args::Tuple) = any(anynan(args), istart:iend)
allnan(istart::Int, iend::Int, args::Tuple) = all(anynan(args), istart:iend)
function Base.iterate(itr::SegmentsIterator, nextidx::Int = 1)
nextidx > itr.n && return nothing
if nextidx == 1 && !any(isempty,itr.args) && anynan(1, itr.args)
nextidx = 2
end
i = findfirst(!anynan(itr.args), nextidx:itr.n)
i === nothing && return nothing
nextval = nextidx + i - 1
i = istart = iend = nextidx
j = findfirst(anynan(itr.args), nextval:itr.n)
nextnan = j === nothing ? itr.n + 1 : nextval + j - 1
# find the next NaN, and iend is the one before
while i <= itr.n + 1
if i > itr.n || anynan(i, itr.args)
# done... array end or found NaN
iend = i-1
break
end
i += 1
end
# find the next non-NaN, and set nextidx
while i <= itr.n
if !anynan(i, itr.args)
break
end
i += 1
end
istart:iend, i
nextval:nextnan-1, nextnan
end
# Find minimal type that can contain NaN and x
@@ -273,6 +258,9 @@ _cycle(v, indices::AVec{Int}) = fill(v, length(indices))
_cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
_as_gradient(grad::ColorGradient) = grad
_as_gradient(c::Colorant) = ColorGradient([c,c])
makevec(v::AVec) = v
makevec(v::T) where {T} = T[v]
@@ -283,18 +271,17 @@ maketuple(x::Tuple{T,S}) where {T,S} = x
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
mapFuncOrFuncs(fs::AVec{F}, u::AVec) where {F<:Function} = [map(f, u) for f in fs]
unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2] for t in xy]
unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
for i in 2:4
@eval begin
unzip(v::Union{AVec{<:Tuple{Vararg{T,$i} where T}},
AVec{<:GeometryTypes.Point{$i}}}) = $(Expr(:tuple, (:([t[$j] for t in v]) for j=1:i)...))
end
end
unzip(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
unzip(xy::FixedSizeArrays.Vec{2,T}) where {T} = T[xy[1]], T[xy[2]]
unzip(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip(xyz::FixedSizeArrays.Vec{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip(xyuv::FixedSizeArrays.Vec{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
unzip(v::Union{AVec{<:GeometryTypes.Point{N}},
AVec{<:Tuple{Vararg{T,N} where T}}}) where N = error("$N-dimensional unzip not implemented.")
unzip(v::Union{AVec{<:GeometryTypes.Point},
AVec{<:Tuple}}) = error("Can't unzip points of different dimensions.")
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x)
@@ -357,6 +344,7 @@ const _scale_base = Dict{Symbol, Real}(
)
function _heatmap_edges(v::AVec)
length(v) == 1 && return v[1] .+ [-0.5, 0.5]
vmin, vmax = ignorenan_extrema(v)
extra_min = (v[2] - v[1]) / 2
extra_max = (v[end] - v[end - 1]) / 2
@@ -369,38 +357,14 @@ function heatmap_edges(v::AVec, scale::Symbol = :identity)
map(invf, _heatmap_edges(map(f,v)))
end
function calc_r_extrema(x, y)
xmin, xmax = ignorenan_extrema(x)
ymin, ymax = ignorenan_extrema(y)
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
ignorenan_extrema(r)
end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
function convert_to_polar(theta, r, r_extrema = ignorenan_extrema(r))
rmin, rmax = r_extrema
theta, r = filter_radial_data(x, y, r_extrema)
r = (r .- rmin) ./ (rmax .- rmin)
x = r.*cos.(theta)
y = r.*sin.(theta)
x, y
end
# Filters radial data for points within the axis limits
function filter_radial_data(theta, r, r_extrema::Tuple{Real, Real})
n = max(length(theta), length(r))
rmin, rmax = r_extrema
x, y = zeros(n), zeros(n)
for i in 1:n
x[i] = _cycle(theta, i)
y[i] = _cycle(r, i)
end
points = map((a, b) -> (a, b), x, y)
filter!(a -> a[2] >= rmin && a[2] <= rmax, points)
x = map(a -> a[1], points)
y = map(a -> a[2], points)
x, y
end
function fakedata(sz...)
y = zeros(sz...)
for r in 2:size(y,1)
@@ -412,14 +376,6 @@ end
isijulia() = :IJulia in nameof.(collect(values(Base.loaded_modules)))
isatom() = :Atom in nameof.(collect(values(Base.loaded_modules)))
function is_installed(pkgstr::AbstractString)
try
Pkg.installed(pkgstr) === nothing ? false : true
catch
false
end
end
istuple(::Tuple) = true
istuple(::Any) = false
isvector(::AVec) = true
@@ -438,7 +394,7 @@ isvertical(series::Series) = isvertical(series.plotattributes)
ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
ticksType(ticks::AVec{T}) where {T<:AbstractString} = :labels
ticksType(ticks::Tuple{T,S}) where {T<:AVec,S<:AVec} = :ticks_and_labels
ticksType(ticks::Tuple{T,S}) where {T<:Union{AVec,Tuple},S<:Union{AVec,Tuple}} = :ticks_and_labels
ticksType(ticks) = :invalid
limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits
@@ -534,7 +490,7 @@ function concatenate_fillrange(x,y::Tuple)
end
function get_sp_lims(sp::Subplot, letter::Symbol)
axis_limits(sp[Symbol(letter, :axis)])
axis_limits(sp, letter)
end
"""
@@ -571,9 +527,9 @@ function get_clims(sp::Subplot)
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface)
for series in series_list(sp)
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Real)
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals.surf)...)
elseif (vals != nothing) && (eltype(vals) <: Real)
elseif (vals != nothing) && (eltype(vals) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...)
end
end
@@ -588,35 +544,50 @@ end
_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax)
function hascolorbar(series::Series)
st = series[:seriestype]
hascbar = st == :heatmap
if st == :contour
hascbar = (isscalar(series[:levels]) ? (series[:levels] > 1) : (length(series[:levels]) > 1)) && (length(unique(Array(series[:z]))) > 1)
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
function colorbar_style(series::Series)
colorbar_entry = series[:colorbar_entry]
if !(colorbar_entry isa Bool)
@warn "Non-boolean colorbar_entry ignored."
colorbar_entry = true
end
if series[:marker_z] != nothing || series[:line_z] != nothing || series[:fill_z] != nothing
hascbar = true
if !colorbar_entry
nothing
elseif isfilledcontour(series)
cbar_fill
elseif iscontour(series)
cbar_lines
elseif series[:seriestype] (:heatmap,:surface) ||
any(series[z] !== nothing for z [:marker_z,:line_z,:fill_z])
cbar_gradient
else
nothing
end
# no colorbar if we are creating a surface LightSource
if xor(st == :surface, series[:fill_z] != nothing)
hascbar = true
end
return hascbar
end
function hascolorbar(sp::Subplot)
cbar = sp[:colorbar]
hascbar = false
if cbar != :none
for series in series_list(sp)
if hascolorbar(series)
hascbar = true
end
hascolorbar(series::Series) = colorbar_style(series) !== nothing
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
iscontour(series::Series) = series[:seriestype] == :contour
isfilledcontour(series::Series) = iscontour(series) && series[:fillrange] !== nothing
function contour_levels(series::Series, clims)
iscontour(series) || error("Not a contour series")
zmin, zmax = clims
levels = series[:levels]
if levels isa Integer
levels = range(zmin, stop=zmax, length=levels+2)
if !isfilledcontour(series)
levels = levels[2:end-1]
end
end
hascbar
levels
end
for comp in (:line, :fill, :marker)
compcolor = string(comp, :color)
@@ -653,6 +624,9 @@ for comp in (:line, :fill, :marker)
end
end
single_color(c, v = 0.5) = c
single_color(grad::ColorGradient, v = 0.5) = grad[v]
function get_linewidth(series, i::Int = 1)
_cycle(series[:linewidth], i)
end
@@ -680,7 +654,7 @@ function has_attribute_segments(series::Series)
end
series[:seriestype] == :shape && return false
# ... else we check relevant attributes if they have multiple inputs
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z, :marker_z))
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z))
end
# ---------------------------------------------------------------
@@ -733,7 +707,7 @@ function with(f::Function, args...; kw...)
# save the backend
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
_pick_default_backend()
end
oldbackend = CURRENT_BACKEND.sym
@@ -745,7 +719,7 @@ function with(f::Function, args...; kw...)
end
# # TODO: generalize this strategy to allow args as much as possible
# # as in: with(:gadfly, :scatter, :legend, :grid) do; ...; end
# # as in: with(:gr, :scatter, :legend, :grid) do; ...; end
# # TODO: can we generalize this enough to also do something similar in the plot commands??
# k = :seriestype
@@ -803,24 +777,24 @@ function debugplots(on = true)
_debugMode.on = on
end
debugshow(x) = show(x)
debugshow(x::AbstractArray) = print(summary(x))
debugshow(io, x) = show(io, x)
debugshow(io, x::AbstractArray) = print(io, summary(x))
function dumpdict(plotattributes::KW, prefix = "", alwaysshow = false)
function dumpdict(io::IO, plotattributes::KW, prefix = "", alwaysshow = false)
_debugMode.on || alwaysshow || return
println()
println(io)
if prefix != ""
println(prefix, ":")
println(io, prefix, ":")
end
for k in sort(collect(keys(plotattributes)))
@printf("%14s: ", k)
debugshow(plotattributes[k])
println()
debugshow(io, plotattributes[k])
println(io)
end
println()
println(io)
end
DD(plotattributes::KW, prefix = "") = dumpdict(plotattributes, prefix, true)
DD(io::IO, plotattributes::KW, prefix = "") = dumpdict(io, plotattributes, prefix, true)
DD(plotattributes::KW, prefix = "") = DD(stdout, plotattributes, prefix)
function dumpcallstack()
error() # well... you wanted the stacktrace, didn't you?!?
@@ -1206,3 +1180,37 @@ end
function construct_categorical_data(x::AbstractArray, axis::Axis)
map(xi -> axis[:discrete_values][searchsortedfirst(axis[:continuous_values], xi)], x)
end
_fmt_paragraph(paragraph::AbstractString;kwargs...) = _fmt_paragraph(IOBuffer(),paragraph,0;kwargs...)
function _fmt_paragraph(io::IOBuffer,
remaining_text::AbstractString,
column_count::Integer;
fillwidth=60,
leadingspaces=0)
kwargs = (fillwidth = fillwidth, leadingspaces = leadingspaces)
m = match(r"(.*?) (.*)",remaining_text)
if isa(m,Nothing)
if column_count + length(remaining_text) fillwidth
print(io,remaining_text)
String(take!(io))
else
print(io,"\n"*" "^leadingspaces*remaining_text)
String(take!(io))
end
else
if column_count + length(m[1]) fillwidth
print(io,"$(m[1]) ")
_fmt_paragraph(io,m[2],column_count + length(m[1]) + 1;kwargs...)
else
print(io,"\n"*" "^leadingspaces*"$(m[1]) ")
_fmt_paragraph(io,m[2],leadingspaces;kwargs...)
end
end
end
function _document_argument(S::AbstractString)
_fmt_paragraph("`$S`: "*_arg_desc[Symbol(S)],leadingspaces = 6 + length(S))
end
+1
View File
@@ -0,0 +1 @@
reference_images
-10
View File
@@ -1,10 +0,0 @@
StatPlots
Images
ImageMagick
@osx QuartzImageIO
FileIO
GR 0.31.0
RDatasets
VisualRegressionTests
UnicodePlots
LaTeXStrings
-35
View File
@@ -1,35 +0,0 @@
using Pkg
# need this to use Conda
# ENV["PYTHON"] = ""
to_add = [
PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"),
# PackageSpec(url="https://github.com/JuliaStats/KernelDensity.jl.git"),
PackageSpec(name="PlotUtils", rev="master"),
PackageSpec(name="RecipesBase", rev="master"),
# PackageSpec(name="Blink", rev="master"),
# PackageSpec(name="Rsvg", rev="master"),
# PackageSpec(name="PlotlyJS", rev="master"),
# PackageSpec(name="VisualRegressionTests", rev="master"),
# PackageSpec("PyPlot"),
# PackageSpec("InspectDR"),
]
if isinteractive()
append!(to_add, [
PackageSpec(name="FileIO"),
PackageSpec(name="ImageMagick"),
PackageSpec(name="UnicodePlots"),
PackageSpec(name="VisualRegressionTests"),
])
end
Pkg.add(to_add)
Pkg.build("ImageMagick")
# Pkg.build("GR")
# Pkg.build("Blink")
# import Blink
# Blink.AtomShell.install()
# Pkg.build("PyPlot")
+32 -34
View File
@@ -1,50 +1,46 @@
import Plots._current_plots_version
using VisualRegressionTests
# using ExamplePlots
if isinteractive()
@eval Main import Gtk
# Taken from MakieGallery
"""
Downloads the reference images from ReferenceImages for a specific version
"""
function download_reference(version = v"0.0.1")
download_dir = abspath(@__DIR__, "reference_images")
isdir(download_dir) || mkpath(download_dir)
tarfile = joinpath(download_dir, "reference_images.zip")
url = "https://github.com/JuliaPlots/PlotReferenceImages.jl/archive/v$(version).tar.gz"
refpath = joinpath(download_dir, "PlotReferenceImages.jl-$(version)")
if !isdir(refpath) # if not yet downloaded
@info "downloading reference images for version $version"
download(url, tarfile)
BinaryProvider.unpack(tarfile, download_dir)
# check again after download
if !isdir(refpath)
error("Something went wrong while downloading reference images. Plots can't be compared to references")
else
rm(tarfile, force = true)
end
else
@info "using reference images for version $version (already downloaded)"
end
refpath
end
# 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
using Plots
# using StatPlots
import PlotReferenceImages
using Random
using Test
default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.17.4"
const ref_image_dir = download_reference()
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2)
Plots._debugMode.on = debug
example = Plots._examples[idx]
Plots.theme(:default)
@info("Testing plot: $pkg:$idx:$(example.header)")
backend(pkg)
backend()
default(size=(500,300))
# ensure consistent results
Random.seed!(1234)
# reference image directory setup
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
refdir = joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots", string(pkg))
refdir = joinpath(ref_image_dir, "Plots", string(pkg))
fn = "ref$idx.png"
# firgure out version info
@@ -76,7 +72,9 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
# test function
func = (fn, idx) -> begin
map(eval, example.exprs)
expr = Expr(:block)
append!(expr.args, example.exprs)
eval(expr)
png(fn)
end
+53 -135
View File
@@ -1,8 +1,12 @@
module PlotsTests
using VisualRegressionTests
using Plots
using Random
using BinaryProvider
using Test
using FileIO
using GeometryTypes
include("add_packages.jl")
include("imgcomp.jl")
# don't actually show the plots
Random.seed!(1234)
default(show=false, reuse=true)
@@ -14,109 +18,25 @@ img_tol = isinteractive() ? 1e-2 : 10e-2
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
@static if Sys.islinux()
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
end
end
#@testset "PyPlot" begin
# @test pyplot() == Plots.PyPlotBackend()
# @test backend() == Plots.PyPlotBackend()
#
# image_comparison_facts(:pyplot, tol=img_tol)
#end
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
# lets just make sure it runs without error
@test isa(plot(rand(10)), Plots.Plot) == true
p = plot(rand(10))
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
p = bar(randn(10))
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
end
# The plotlyjs testimages return a connection error on travis:
# connect: connection refused (ECONNREFUSED)
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# if Sys.islinux() && isinteractive()
# image_comparison_facts(:plotlyjs,
# skip=[
# 2, # animation (skipped for speed)
# 27, # (polar plots) takes very long / not working
# 31, # animation (skipped for speed)
# ],
# tol=img_tol)
# end
# end
# InspectDR returns that error on travis:
# ERROR: LoadError: InitError: Cannot open display:
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
# @testset "InspectDR" begin
# @test inspectdr() == Plots.InspectDRBackend()
# @test backend() == Plots.InspectDRBackend()
#
# image_comparison_facts(:inspectdr,
# skip=[
# 2, # animation
# 6, # heatmap not defined
# 10, # heatmap not defined
# 22, # contour not defined
# 23, # pie not defined
# 27, # polar plot not working
# 28, # heatmap not defined
# 31, # animation
# ],
# tol=img_tol)
# end
# @testset "Plotly" begin
# @test plotly() == Plots.PlotlyBackend()
# @test backend() == Plots.PlotlyBackend()
#
# # # until png generation is reliable on OSX, just test on linux
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
# end
# @testset "Immerse" begin
# @test immerse() == Plots.ImmerseBackend()
# @test backend() == Plots.ImmerseBackend()
#
# # as long as we can plot anything without error, it should be the same as Gadfly
# image_comparison_facts(:immerse, only=[1], tol=img_tol)
# end
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# # as long as we can plot anything without error, it should be the same as Plotly
# image_comparison_facts(:plotlyjs, only=[1], tol=img_tol)
# end
# @testset "Gadfly" begin
# @test gadfly() == Plots.GadflyBackend()
# @test backend() == Plots.GadflyBackend()
#
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
#
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], tol=img_tol)
# end
@testset "Axes" begin
p = plot()
axis = p.subplots[1][:xaxis]
@@ -132,46 +52,44 @@ end
end
@testset "NoFail" begin
histogram([1, 0, 0, 0, 0, 0])
plots = [histogram([1, 0, 0, 0, 0, 0]),
plot([missing]),
plot([missing; 1:4]),
plot([fill(missing,10); 1:4]),
plot([1 1; 1 missing]),
plot(["a" "b"; missing "d"], [1 2; 3 4])]
for plt in plots
display(plt)
end
end
# tests for preprocessing recipes
@testset "Segments" begin
function segments(args...)
segs = UnitRange{Int}[]
for seg in iter_segments(args...)
push!(segs,seg)
end
segs
end
# @testset "recipes" begin
nan10 = fill(NaN,10)
@test segments(11:20) == [1:10]
@test segments([NaN]) == []
@test segments(nan10) == []
@test segments([nan10; 1:5]) == [11:15]
@test segments([1:5;nan10]) == [1:5]
@test segments([nan10; 1:5; nan10; 1:5; nan10]) == [11:15, 26:30]
@test segments([NaN; 1], 1:10) == [2:2, 4:4, 6:6, 8:8, 10:10]
@test segments([nan10; 1:15], [1:15; nan10]) == [11:15]
end
# user recipe
# type T end
# @recipe function f(::T)
# line := (3,0.3,:red)
# marker := (20,0.5,:blue,:o)
# bg := :yellow
# rand(10)
# end
# plot(T())
# plot recipe
# @recipe function f(::Type{Val{:hiplt}},plt::Plot)
# line := (3,0.3,:red)
# marker := (20,0.5,:blue,:o)
# t := :path
# bg:=:green
# ()
# end
# plot(rand(10),t=:hiplt)
# series recipe
# @recipe function f(::Type{Val{:hi}},x,y,z)
# line := (3,0.3,:red)
# marker := (20,0.5,:blue,:o)
# t := :path
# ()
# end
# plot(rand(10),t=:hiplt)
# end
end # module
@testset "Utils" begin
zipped = ([(1,2)], [("a","b")], [(1,"a"),(2,"b")],
[(1,2),(3,4)], [(1,2,3),(3,4,5)], [(1,2,3,4),(3,4,5,6)],
[(1,2.0),(missing,missing)], [(1,missing),(missing,"a")],
[(missing,missing)], [(missing,missing,missing),("a","b","c")])
for z in zipped
@test isequal(collect(zip(Plots.unzip(z)...)), z)
@test isequal(collect(zip(Plots.unzip(Point.(z))...)), z)
end
end
-36
View File
@@ -1,36 +0,0 @@
import SnoopCompile
### Log the compiles
# This only needs to be run once (to generate "/tmp/plots_compiles.csv")
# SnoopCompile.@snoop "/tmp/plots_compiles.csv" begin
# include(joinpath(dirname(@__FILE__), "runtests.jl"))
# end
# ----------------------------------------------------------
### Parse the compiles and generate precompilation scripts
# This can be run repeatedly to tweak the scripts
# IMPORTANT: we must have the module(s) defined for the parcelation
# step, otherwise we will get no precompiles for the Plots module
using Plots
data = SnoopCompile.read("/tmp/plots_compiles.csv")
# The Plots tests are run inside a module PlotsTest, so all
# the precompiles get credited to PlotsTest. Credit them to Plots instead.
subst = Dict("PlotsTests"=>"Plots")
# Blacklist helps fix problems:
# - MIME uses type-parameters with symbols like :image/png, which is
# not parseable
blacklist = ["MIME"]
# Use these two lines if you want to create precompile functions for
# individual packages
pc, discards = SnoopCompile.parcel(data[end:-1:1,2], subst=subst, blacklist=blacklist)
SnoopCompile.write("/tmp/precompile", pc)
pdir = joinpath(dirname(@__FILE__), "..")
run(`cp /tmp/precompile/precompile_Plots.jl $pdir/src/precompile.jl`)