Compare commits

..

131 Commits

Author SHA1 Message Date
Christopher Rackauckas 4bcf43c84b Update imgcomp.jl 2018-03-31 09:11:02 -07:00
Daniel Schwabeneder bfc26fa407 Merge pull request #1445 from daschw/infinite-objects
Infinite objects (fix #1422)
2018-03-28 21:49:32 +02:00
Daniel Schwabeneder e7b435b47f Merge pull request #1454 from CarloLucibello/master
import filter from Base
2018-03-28 21:48:51 +02:00
CarloLucibello dd6842522f avoid import 2018-03-28 09:50:46 -07:00
Daniel Schwabeneder f56d944870 hspan and vspan recipes 2018-03-28 11:32:23 +02:00
Daniel Schwabeneder 772b79306d Merge pull request #1460 from daschw/pyplot-marker_z
PyPlot: fix markercolor in legend for marker_z with st = :path
2018-03-28 10:53:23 +02:00
Daniel Schwabeneder 4ef2c6286b Merge pull request #1459 from daschw/mplot3d
import mplot3d in pyplot (fix #1457)
2018-03-27 15:45:02 +02:00
Daniel Schwabeneder a5f7c1b867 fix markercolor in legend for marker_z with st = :path 2018-03-27 14:24:26 +02:00
Daniel Schwabeneder 4d8ef2a008 import mplot3d in pyplot 2018-03-27 13:41:18 +02:00
CarloLucibello 8bc28d472f import filter 2018-03-24 19:12:18 -04:00
piever 3753ab1b55 increase version number for tests 2018-03-22 20:37:27 +00:00
Pietro Vertechi babc600915 Merge pull request #1450 from JuliaPlots/pv/release
update news
2018-03-22 14:22:03 -06:00
piever b2f92e246e update news 2018-03-22 19:39:18 +00:00
Daniel Schwabeneder 0ace28b784 extend straightline data beyond axes limits 2018-03-21 11:42:01 +01:00
Daniel Schwabeneder 004ad15875 Merge pull request #1437 from daschw/plotly-bar
RFC: use bar recipe in plotly
2018-03-20 17:11:37 +01:00
Daniel Schwabeneder 1c0a731ff6 fix typo in glvisualize 2018-03-19 21:51:02 +01:00
Daniel Schwabeneder 9a5f42c251 infinite shapes 2018-03-19 21:34:55 +01:00
Daniel Schwabeneder c8cdade884 :straightline for all backends 2018-03-19 16:24:23 +01:00
Daniel Schwabeneder bbff66a041 glvisualize() :straightline 2018-03-19 14:55:38 +01:00
Daniel Schwabeneder d11c6a20bf Merge pull request #1438 from daschw/categorical-ticks
allow ticks = :all and ticks = n::Int for categorical axes
2018-03-18 23:21:44 +01:00
Daniel Schwabeneder 6c396e1d88 Merge pull request #1436 from daschw/fill-magic
fix fill magic argument
2018-03-18 23:21:16 +01:00
Daniel Schwabeneder bffd9bcb53 :straightline seriestype and gr implementation 2018-03-18 23:15:45 +01:00
Andrew Palugniok 7cee448d68 Merge pull request #1378 from apalugniok/dynamic-link-axes
Implement synchronized interactive linked axes for PyPlot and Plotly.
2018-03-18 19:48:09 +00:00
Daniel Schwabeneder 047a13a8dc Merge pull request #1430 from yakir12/patch-2
add option to supress saved message
2018-03-16 11:28:28 +01:00
Daniel Schwabeneder 717aed5a06 allow ticks = :all and ticks = n::Int for categorical axes 2018-03-16 11:26:56 +01:00
Daniel Schwabeneder 7d58090e59 use bar recipe in plotly 2018-03-16 09:36:24 +01:00
Daniel Schwabeneder 501df8cfb9 allow passing Real or 2Tuple of Reals as fillrange for Plotly 2018-03-15 21:46:19 +01:00
Daniel Schwabeneder 7f6fe09a00 fix magic fill argument 2018-03-15 21:22:29 +01:00
Andrew Palugniok d183d579cf Link axes before adding series. 2018-03-15 19:13:38 +01:00
Yakir Luc Gagnon bfa2fd2edc add option to supress saved message
Added option `show_msg::Bool` to `buildanimation` to show/suppress the "Saved animation to..." message.
2018-03-14 12:01:01 +01:00
Pietro Vertechi 7c257a09f6 Partially address #1409: group with named tuples (#1429)
* group with named tuples

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

closes #1418

closes #1386
2018-02-28 17:26:53 -05:00
Daniel Schwabeneder c74adc6521 check if a vector of the color black is passed to gr contour 2018-02-28 23:00:46 +01:00
Daniel Schwabeneder 7cc60d0b0c fix single-color case for plotly 2018-02-28 22:53:36 +01:00
Daniel Schwabeneder d8f0612f5a implement contour_labels and partially vector of colors for Plotly(JS) 2018-02-28 22:51:06 +01:00
Daniel Schwabeneder cd4b41a537 allow to pass a vector of colors for contour lines in PyPlot 2018-02-28 22:25:06 +01:00
Daniel Schwabeneder fdb2ee2847 implement contour_labels for PyPlot and fix #1091 2018-02-28 22:10:45 +01:00
Daniel Schwabeneder 9c4cc5acda GR colorbar fixees 2018-02-28 21:27:34 +01:00
Daniel Schwabeneder f901254519 add contour_labels attribute and minor GR contour fixes 2018-02-28 21:19:18 +01:00
Daniel Schwabeneder 18032bb9af Merge pull request #1414 from daschw/bar
default bar width for plots with only one bar (fix #1413)
2018-02-26 10:32:06 +01:00
Daniel Schwabeneder a7a5fe36f9 default to a bar width of _bar_width for bar plots with only one data point 2018-02-26 10:03:02 +01:00
Daniel Schwabeneder 32e1536955 Merge pull request #1411 from daschw/pyplot-marker
replace hline and vline marker shapes with _ and | on pyplot (fix #1188)
2018-02-26 09:15:55 +01:00
Daniel Schwabeneder 77c2ee6782 replace hline and vline marker shapes with _ and | on pyplot 2018-02-25 09:52:26 +01:00
Andrew Palugniok dbe5b78307 Merge pull request #1395 from apalugniok/native-ticks
Add :native option to ticks attribute (Fixes #1382)
2018-02-24 13:41:56 +00:00
Michael Krabbe Borregaard 9578fe03b9 Merge pull request #1408 from piever/plotlyjs
make plotlyjs use html in ijulia
2018-02-24 12:09:04 +01:00
piever ef48b66ac4 fix plotly 2018-02-24 01:55:59 +00:00
piever b9d586c009 make plotlyjs use html in ijulia 2018-02-24 01:35:30 +00:00
Andrew Palugniok 1d51982cb0 Fix non-native lims for ticks = :native on PyPlot. 2018-02-23 10:56:57 +00:00
Daniel Schwabeneder 046985277d Merge pull request #1399 from massemanet/fix-ijulia-integration
fix IJulia integration (fix #1365)
2018-02-23 11:44:16 +01:00
Daniel Schwabeneder d679337700 Merge pull request #1405 from daschw/contour
Make contourf work with uniform data
2018-02-23 11:01:56 +01:00
Daniel Schwabeneder 2d5f896069 Merge pull request #1403 from daschw/pyplot-colorbar
reduce pyplot colorbar size for z values with very small or big abs vals
2018-02-23 11:01:24 +01:00
Daniel Schwabeneder de51beebe8 ensure non-unique clims 2018-02-21 17:47:11 +01:00
Andrew Palugniok 80b25657bc Merge pull request #1401 from apalugniok/pgfplots-extra-brackets
Prevent addition of curly braces around style string. (Fixes #1396)
2018-02-21 16:09:46 +00:00
Daniel Schwabeneder 0db60348aa reduce pyplot colorbar size for z values with very small or big absolute values 2018-02-21 17:03:23 +01:00
Andrew Palugniok 5017024557 Fix handling of discrete values with ticks = :native for Plotly. 2018-02-21 14:50:32 +00:00
Andrew Palugniok 94863d69b1 Consider all ticks = false aliases in backends. 2018-02-21 10:17:13 +00:00
Andrew Palugniok 06466b060f Implement :native ticks option. 2018-02-21 10:09:57 +00:00
Daniel Schwabeneder 3ac9f3d9cc Merge pull request #1376 from grahamas/master
Allow animation frame saving frequency to be a variable.
2018-02-20 09:29:13 +01:00
Daniel Schwabeneder d335a0221d Merge pull request #1398 from daschw/time
add Dates.Time recipe (fix #1391)
2018-02-20 09:27:02 +01:00
Daniel Schwabeneder a118d73871 Merge pull request #1400 from daschw/step-ribbon
consider fillrange in step recipes (fix #1393)
2018-02-20 09:26:07 +01:00
Daniel Schwabeneder 6c13d87a00 remove old make_steps function 2018-02-18 22:59:37 +01:00
Daniel Schwabeneder 9e2264c841 consider fillrange in step recipes 2018-02-18 22:49:27 +01:00
Daniel Schwabeneder c0248069a1 add Dates.Time recipe 2018-02-17 23:33:55 +01:00
Andrew Palugniok 5ba4c10a18 Prevent addition of curly braces around style string. 2018-02-17 17:32:53 +00:00
mats cronqvist 82ceb71bd0 fix IJulia integration 2018-02-16 14:46:45 +01:00
Andrew Palugniok a4636fd88d Merge pull request #1390 from apalugniok/plotly-annotations
Fix misplaced Plotly annotations. (Fixes #1356)
2018-02-11 19:08:18 +00:00
Andrew Palugniok e19e25473c Fix misplaced Plotly annotations. 2018-02-11 10:36:12 +00:00
Graham A Smith 11a856fbb3 Allow animation frame saving frequency to be a variable. 2018-01-31 13:12:32 -06:00
Andrew Palugniok 1ed7899296 Merge pull request #1362 from apalugniok/cropped-image
Fix image axis limits and add image movement and resizing.
2018-01-19 15:41:41 +00:00
Andrew Palugniok a79a40b1e8 Allow manual flipping of yaxis for images. 2018-01-18 18:21:26 +00:00
Andrew Palugniok d4075a1ef5 Allow movement and resizing of images. 2018-01-18 16:23:39 +00:00
Andrew Palugniok 99f3b7ae99 Fix axis limits for images. 2018-01-18 16:23:39 +00:00
Daniel Schwabeneder fcb5b355b1 Merge pull request #1361 from daschw/group
fix grouping of series_annotations
2018-01-18 11:13:43 +01:00
Daniel Schwabeneder 43d26af34d Merge pull request #1360 from daschw/pyplot
Update pyplot backend
2018-01-18 11:06:27 +01:00
Daniel Schwabeneder 5e1c67c042 fix grouping of series_annotations 2018-01-18 10:44:35 +01:00
Daniel Schwabeneder 11ef2be506 update pyart3D 2018-01-17 15:18:36 +01:00
Andrew Palugniok 0f9bb7793c Merge pull request #1331 from apalugniok/subplot-labeling
RFC: Subplot labeling. Fixes #998
2018-01-15 23:02:40 +00:00
Daniel Schwabeneder decd7c2f60 Merge pull request #1354 from apalugniok/cropped-image
Fix axis limits not cropping image. Fixes #1296
2018-01-15 14:35:48 +01:00
Daniel Schwabeneder edf88ffdf6 Merge pull request #1353 from wkearn/wsk-bugfix-1329
Check if any of the iterator args are zero
2018-01-15 14:34:49 +01:00
Daniel Schwabeneder 435a7c809b Merge pull request #1352 from wkearn/wsk-bugfix-1823
Uncomment convertToAnyVector for Date/DateTime
2018-01-15 14:34:32 +01:00
Andrew Palugniok d79c66e5b6 Add position aliases. 2018-01-14 11:46:41 +00:00
Andrew Palugniok 10a8520805 Add subplot labeling via annotations. 2018-01-14 11:46:41 +00:00
Will Kearney cf6c16102b Use isempty rather than iszero 2018-01-13 13:57:03 -05:00
Will Kearney 32baaea5cb Check if any of the iterator args are zero
Fixes #1329
2018-01-13 11:20:33 -05:00
Andrew Palugniok 27e2795576 Fix deprecation. 2018-01-13 16:18:08 +00:00
Andrew Palugniok c21f3810b9 Fix axis limits not cropping image. 2018-01-13 15:44:52 +00:00
Will Kearney 877e7ab940 Uncomment convertToAnyVector for Date/DateTime
Fixes #1283
2018-01-13 10:07:27 -05:00
Daniel Schwabeneder 7a9a871be3 Merge pull request #1351 from daschw/gr-loglabels
gr: fix labels with logscales
2018-01-11 22:23:15 +01:00
Daniel Schwabeneder de31ce1c73 Merge pull request #1350 from daschw/tests
update version for tests
2018-01-11 22:16:59 +01:00
Daniel Schwabeneder 8b6dba8301 fix labels with logscales 2018-01-11 21:26:33 +01:00
Daniel Schwabeneder af859b4c13 update version in NEWS.md 2018-01-11 20:30:47 +01:00
Daniel Schwabeneder 9b5295ff00 update version for tests 2018-01-11 20:11:59 +01:00
Josef Heinen c1a94d704e Merge pull request #1349 from jheinen/master
fixed problems with labels in scientific notation
2018-01-11 03:45:24 +01:00
Josef Heinen c2b56878fc fixed problems with labels in scientific notation 2018-01-10 20:30:10 +01:00
Josef Heinen 4757bd89c0 Merge pull request #1249 from apalugniok/pgfplots-scaled-ticks
WIP: Fix scientific formatter for PGFPlots and GR. Fixes #1241
2018-01-10 19:05:13 +01:00
Michael Krabbe Borregaard 1e56bf939d Merge pull request #1347 from mkborregaard/master
update news for 0.14.3
2018-01-10 11:38:38 +01:00
Michael K. Borregaard dbd5ae46dd update news 2018-01-10 11:38:11 +01:00
Daniel Schwabeneder 7c6095b6e8 Merge pull request #1344 from daschw/heatmap-alpha
allow transparency in heatmaps (fix #1342)
2018-01-09 10:19:04 +02:00
Daniel Schwabeneder 04888646e7 fix gr 2018-01-08 13:50:16 +01:00
Daniel Schwabeneder f6ed3fbb76 allow transparency in heatmaps 2018-01-08 12:50:46 +01:00
Daniel Schwabeneder 7bf2918438 Merge pull request #1324 from wkearn/plotlyjs_rgba
Map rgba_string over :color vector and cycle through result
2018-01-08 12:44:47 +02:00
Daniel Schwabeneder 92fefc7089 Merge pull request #1340 from wkearn/framestyle_ticks
Add a check for ticks==nothing or false
2018-01-08 11:51:10 +02:00
Will Kearney e6df4d977d Add a check for ticks==nothing or false
Fixes #1336
2018-01-06 14:54:57 -05:00
Andrew Palugniok 62ca787e6e Fix scientific formatter for GR and PGFPlots. 2017-12-23 00:35:44 +00:00
Andrew Palugniok 32d59fff61 Turn off scaled ticks for PGFPlots. 2017-12-22 23:29:50 +00:00
Andrew Palugniok 1949b6fe0f Merge pull request #1330 from apalugniok/pyplot-alphaImages
Fix PyPlot ignoring alpha values of images. Fixes #1131
2017-12-19 14:19:32 +00:00
Andrew Palugniok 95a5b5025a Fix PyPlot ignoring alpha values of images 2017-12-19 12:05:11 +00:00
Daniel Schwabeneder aa22fd2ff2 Merge pull request #1328 from daschw/gr-grid3d
fix gr 3d grid appearance
2017-12-18 22:57:47 +01:00
Daniel Schwabeneder 50df9a70c9 fix gr 3d grid appearance 2017-12-18 22:15:57 +01:00
Michael Krabbe Borregaard 6d88e150d0 Merge pull request #1327 from mkborregaard/master
Don't return false from abline!
2017-12-18 09:20:36 +01:00
Michael K. Borregaard b1817e513b Don't return false 2017-12-18 09:19:31 +01:00
Michael Krabbe Borregaard ce737a9491 Merge pull request #1326 from mkborregaard/master
Don't add `abline!` if outside plot window
2017-12-18 09:17:36 +01:00
Michael K. Borregaard 6ff4dce62a Don't add abline! if outside plot window 2017-12-18 09:16:51 +01:00
Will Kearney 89b5582d0d Map rgba_string over :color vector and cycle through result 2017-12-17 16:13:35 -05:00
Daniel Schwabeneder 09c5e8a375 Merge pull request #1323 from daschw/plottheme
Reduce number of ticks in heatmap in showtheme recipe
2017-12-17 17:21:18 +01:00
Daniel Schwabeneder a1a7dcd6b8 reduce tick number in heatmap plot 2017-12-17 17:04:05 +01:00
Daniel Schwabeneder d223d872fb Merge pull request #1322 from daschw/line_z
Fix line_z
2017-12-17 17:01:28 +01:00
Andrew Palugniok 91eaa32ad7 Merge pull request #1320 from apalugniok/pyplot-legend
Fix mismatched legend color when linecolor is given. Fixes #1319
2017-12-17 16:00:08 +00:00
Daniel Schwabeneder 6cdccf4353 add missing 'series' 2017-12-17 16:44:20 +01:00
Josef Heinen ac9aee97fd Merge pull request #1318 from jheinen/master
gr: improve PNG output (resolution)
2017-12-17 13:07:16 +01:00
Josef Heinen 5be95be9ae gr: improve PNG output (resolution) 2017-12-17 12:52:20 +01:00
Andrew Palugniok e402f5dfce Fix mismatched legend color when linecolor is given. 2017-12-16 20:11:11 +00:00
Michael Krabbe Borregaard 61be113714 Merge pull request #1317 from apalugniok/3d-marker_z
3D marker_z handling. Fixes #1205
2017-12-16 10:08:13 +01:00
Andrew Palugniok a637f43edd Only base clims on z values when series is colored by z. 2017-12-15 22:49:46 +00:00
Daniel Schwabeneder 4bb43887a4 Merge pull request #1314 from daschw/showtheme
update showtheme recipe
2017-12-15 14:04:19 +01:00
Daniel Schwabeneder 802b20be6f update showtheme recipe 2017-12-15 10:30:56 +01:00
Michael K. Borregaard 216a9c3666 reactivate precompilation 2017-12-15 09:24:00 +01:00
24 changed files with 679 additions and 220 deletions
+29 -1
View File
@@ -3,7 +3,7 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.14!
- All new development should target 0.15!
- Minor version 0.11 is the last one to support Julia 0.5!!
- Critical bugfixes only
- `backports` branch is for Julia 0.5
@@ -11,6 +11,34 @@
---
## (current master)
## 0.15.1
- fix scientific notation for labels in GR
- fix labels with logscale
- fix image cropping with GR
- fix grouping of annotations
- fix annotations in Plotly
- allow saving notebook with plots as pdf from IJulia
- fix fillrange and ribbon for step recipes
- implement native ticks that respond to zoom
- fix bar plot with one bar
- contour labels and colorbar fixes
- interactive linked axis for PyPlot
- add `NamedTuple` syntax to group with named legend
- use bar recipe in Plotly
- implement categorical ticks
## 0.15.0
- improve resolution of png output of GR with savefig()
- add check for ticks=nothing
- allow transparency in heatmaps
- fix line_z for GR
- fix legendcolor for pyplot
- fix pyplot ignoring alpha values of images
- don't let `abline!` change subplot limits
- update showtheme recipe
## 0.14.2
- fix plotly bar lines bug
+4 -1
View File
@@ -1,4 +1,4 @@
__precompile__(false)
__precompile__(true)
module Plots
@@ -14,6 +14,7 @@ using Base.Meta
@reexport using PlotThemes
import Showoff
import StatsBase
import JSON
using Requires
@@ -186,6 +187,8 @@ include("output.jl")
@shorthands sticks
@shorthands hline
@shorthands vline
@shorthands hspan
@shorthands vspan
@shorthands ohlc
@shorthands contour
@shorthands contourf
+6 -3
View File
@@ -68,7 +68,8 @@ mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn, false;
function buildanimation(animdir::AbstractString, fn::AbstractString,
is_animated_gif::Bool=true;
fps::Integer = 20, loop::Integer = 0,
variable_palette::Bool=false)
variable_palette::Bool=false,
show_msg::Bool=true)
fn = abspath(fn)
if is_animated_gif
@@ -86,7 +87,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString,
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
end
info("Saved animation to ", fn)
show_msg && info("Saved animation to ", fn)
AnimatedGif(fn)
end
@@ -115,6 +116,7 @@ function _animate(forloop::Expr, args...; callgif = false)
# add the call to frame to the end of each iteration
animsym = gensym("anim")
countersym = gensym("counter")
freqassert = :()
block = forloop.args[2]
# create filter
@@ -127,7 +129,7 @@ function _animate(forloop::Expr, args...; callgif = false)
# filter every `freq` frames (starting with the first frame)
@assert n == 2
freq = args[2]
@assert isa(freq, Integer) && freq > 0
freqassert = :(@assert isa($freq, Integer) && $freq > 0)
:(mod1($countersym, $freq) == 1)
elseif args[1] == :when
@@ -147,6 +149,7 @@ function _animate(forloop::Expr, args...; callgif = false)
# full expression:
esc(quote
$freqassert # if filtering, check frequency is an Integer > 0
$animsym = Animation() # init animation object
$countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
+1
View File
@@ -43,6 +43,7 @@ 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?",
: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.",
+40 -8
View File
@@ -159,6 +159,21 @@ const _markerAliases = Dict{Symbol,Symbol}(
:spike => :vline,
)
const _positionAliases = Dict{Symbol,Symbol}(
:top_left => :topleft,
:tl => :topleft,
:top_center => :topcenter,
:tc => :topcenter,
:top_right => :topright,
:tr => :topright,
:bottom_left => :bottomleft,
:bl => :bottomleft,
:bottom_center => :bottomcenter,
:bc => :bottomcenter,
:bottom_right => :bottomright,
:br => :bottomright,
)
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
const _logScales = [:ln, :log2, :log10]
const _logScaleBases = Dict(:ln => e, :log2 => 2.0, :log10 => 10.0)
@@ -257,6 +272,7 @@ const _series_defaults = KW(
:normalize => false, # do we want a normalized histogram?
:weights => nothing, # optional weights for histograms (1D and 2D)
:contours => false, # add contours to 3d surface and wireframe plots
:contour_labels => false,
:match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
:subplot => :auto, # which subplot(s) does this series belong to?
@@ -559,6 +575,7 @@ add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls,
add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border)
add_aliases(:tick_direction, :tickdirection, :tick_dir, :tickdir, :tick_orientation, :tickorientation, :tick_or, :tickor)
add_aliases(:camera, :cam, :viewangle, :view_angle)
add_aliases(:contour_labels, :contourlabels, :clabels, :clabs)
# add all pluralized forms to the _keyAliases dict
for arg in keys(_series_defaults)
@@ -734,6 +751,10 @@ function processFillArg(d::KW, arg)
elseif allAlphas(arg)
d[:fillalpha] = arg
# fillrange provided as vector or number
elseif typeof(arg) <: Union{AbstractArray{<:Real}, Real}
d[:fillrange] = arg
elseif !handleColors!(d, arg, :fillcolor)
d[:fillrange] = arg
@@ -995,15 +1016,28 @@ function extractGroupArgs(v::AVec, args...; legendEntry = string)
GroupBy(map(legendEntry, groupLabels), groupIds)
end
legendEntryFromTuple(ns::Tuple) = string(("$n " for n in ns)...)
legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
# this is when given a tuple of vectors of values to group by
function extractGroupArgs(vs::Tuple, args...)
(vs == ()) && return GroupBy([""], [1:size(args[1],1)])
v = collect(zip(vs...))
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
v = map(tuple, vs...)
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
# allow passing NamedTuples for a named legend entry
@require NamedTuples begin
legendEntryFromTuple(ns::NamedTuples.NamedTuple) =
join(["$k = $v" for (k, v) in zip(keys(ns), values(ns))], ", ")
function extractGroupArgs(vs::NamedTuples.NamedTuple, args...)
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
NT = eval(:(NamedTuples.@NT($(keys(vs)...)))){map(eltype, vs)...}
v = map(NT, vs...)
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
end
# expecting a mapping of "group label" to "group indices"
function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
groupLabels = sortedkeys(idxmap)
@@ -1294,11 +1328,9 @@ end
function _update_subplot_periphery(sp::Subplot, anns::AVec)
# extend annotations, and ensure we always have a (x,y,PlotText) tuple
newanns = vcat(anns, sp[:annotations])
for (i,ann) in enumerate(newanns)
x,y,tmp = ann
ptxt = isa(tmp, PlotText) ? tmp : text(tmp)
newanns[i] = (x,y,ptxt)
newanns = []
for ann in vcat(anns, sp[:annotations])
append!(newanns, process_annotation(sp, ann...))
end
sp.attr[:annotations] = newanns
+24 -16
View File
@@ -234,11 +234,22 @@ function get_ticks(axis::Axis)
ticks = _transform_ticks(axis[:ticks])
ticks in (nothing, false) && return nothing
# treat :native ticks as :auto
ticks = ticks == :native ? :auto : ticks
dvals = axis[:discrete_values]
cv, dv = if !isempty(dvals) && ticks == :auto
cv, dv = if !isempty(dvals)
# discrete ticks...
axis[:continuous_values], dvals
elseif ticks == :auto
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in linspace(1, n, 15)]
elseif ticks == :all
1:n
elseif typeof(ticks) <: Int
Int[round(Int,i) for i in linspace(1, n, ticks)]
end
axis[:continuous_values][rng], dvals[rng]
elseif typeof(ticks) <: Symbol
if ispolar(axis.sps[1]) && axis[:letter] == :x
#force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
@@ -257,13 +268,7 @@ function get_ticks(axis::Axis)
end
# @show ticks dvals cv dv
# TODO: better/smarter cutoff values for sampling ticks
if length(cv) > 30 && ticks == :auto
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)]
cv[rng], dv[rng]
else
cv, dv
end
return cv, dv
end
_transform_ticks(ticks) = ticks
@@ -284,8 +289,8 @@ end
function expand_extrema!(ex::Extrema, v::Number)
ex.emin = NaNMath.min(v, ex.emin)
ex.emax = NaNMath.max(v, ex.emax)
ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin
ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax
ex
end
@@ -300,8 +305,8 @@ expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
ex = axis[:extrema]
ex.emin = NaNMath.min(v[1], ex.emin)
ex.emax = NaNMath.max(v[2], ex.emax)
ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin
ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax
ex
end
function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
@@ -323,6 +328,9 @@ function expand_extrema!(sp::Subplot, d::KW)
else
letter == :x ? :y : letter == :y ? :x : :z
end]
if letter != :z && d[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
data = [NaN]
end
axis = sp[Symbol(letter, "axis")]
if isa(data, Volume)
@@ -552,7 +560,7 @@ 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 && length(xticks) > 1
if sp[:framestyle] == :origin && !(xticks in (nothing,false)) && length(xticks) > 1
showticks = xticks[1] .!= 0
xticks = (xticks[1][showticks], xticks[2][showticks])
end
@@ -591,7 +599,7 @@ 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 && length(yticks) > 1
if sp[:framestyle] == :origin && !(yticks in (nothing,false)) && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
+11 -5
View File
@@ -51,7 +51,7 @@ const _glvisualize_attr = merge_with_base_supported([
:tick_direction,
])
const _glvisualize_seriestype = [
:path, :shape,
:path, :shape, :straightline,
:scatter, :hexbin,
:bar, :boxplot,
:heatmap, :image, :volume,
@@ -287,7 +287,13 @@ function topoints(::Type{P}, array) where P
end
function extract_points(d)
dim = is3d(d) ? 3 : 2
array = (d[:x], d[:y], d[:z])[1:dim]
array = if d[:seriestype] == :straightline
straightline_data(d)
elseif d[:seriestype] == :shape
shape_data(d)
else
(d[:x], d[:y], d[:z])[1:dim]
end
topoints(Point{dim, Float32}, array)
end
function make_gradient(grad::Vector{C}) where C <: Colorant
@@ -1102,7 +1108,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
kw_args[:stroke_width] = Float32(d[:linewidth]/100f0)
end
vis = GL.gl_surface(x, y, z, kw_args)
elseif (st in (:path, :path3d)) && d[:linewidth] > 0
elseif (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
kw = copy(kw_args)
points = Plots.extract_points(d)
extract_linestyle(d, kw)
@@ -1215,7 +1221,7 @@ end
function gl_image(img, kw_args)
rect = kw_args[:primitive]
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(rect.x, rect.y, rect.h, rect.w) # seems to be flipped
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(rect.x, rect.y, rect.w, rect.h)
visualize(img, Style(:default), kw_args)
end
@@ -1460,7 +1466,7 @@ function make_label(sp, series, i)
d = series.d
st = d[:seriestype]
kw_args = KW()
if (st in (:path, :path3d)) && d[:linewidth] > 0
if (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
points = Point2f0[(0, ho), (w, ho)]
kw = KW()
extract_linestyle(d, kw)
+76 -29
View File
@@ -45,9 +45,10 @@ const _gr_attr = merge_with_base_supported([
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _gr_seriestype = [
:path, :scatter,
:path, :scatter, :straightline,
:heatmap, :pie, :image,
:contour, :path3d, :scatter3d, :surface, :wireframe,
:shape
@@ -193,7 +194,7 @@ gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
function gr_inqtext(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.inqtextext(x, y, s[2:end-1])
elseif search(s, '\\') != 0
elseif search(s, '\\') != 0 || contains(s, "10^{")
GR.inqtextext(x, y, s)
else
GR.inqtext(x, y, s)
@@ -205,7 +206,7 @@ gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
function gr_text(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.mathtex(x, y, s[2:end-1])
elseif search(s, '\\') != 0
elseif search(s, '\\') != 0 || contains(s, "10^{")
GR.textext(x, y, s)
else
GR.text(x, y, s)
@@ -222,6 +223,9 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
sinf = sind.(a)
cosf = cosd.(a)
rtick_values, rtick_labels = get_ticks(yaxis)
if yaxis[:formatter] == :scientific && yaxis[:ticks] in (:auto, :native)
rtick_labels = convert_sci_unicode(rtick_labels)
end
#draw angular grid
if xaxis[:grid]
@@ -543,7 +547,7 @@ function gr_set_gradient(c)
end
# this is our new display func... set up the viewport_canvas, compute bounding boxes, and display each subplot
function gr_display(plt::Plot)
function gr_display(plt::Plot, fmt="")
GR.clearws()
# collect some monitor/display sizes in meters and pixels
@@ -554,17 +558,25 @@ function gr_display(plt::Plot)
# compute the viewport_canvas, normalized to the larger dimension
viewport_canvas = Float64[0,1,0,1]
w, h = plt[:size]
if !haskey(ENV, "PLOTS_TEST")
dpi_factor = plt[:dpi] / DPI
if fmt == "png"
dpi_factor *= 6
end
else
dpi_factor = 1
end
gr_plot_size[:] = [w, h]
if w > h
ratio = float(h) / w
msize = display_width_ratio * w
msize = display_width_ratio * w * dpi_factor
GR.setwsviewport(0, msize, 0, msize * ratio)
GR.setwswindow(0, 1, 0, ratio)
viewport_canvas[3] *= ratio
viewport_canvas[4] *= ratio
else
ratio = float(w) / h
msize = display_height_ratio * h
msize = display_height_ratio * h * dpi_factor
GR.setwsviewport(0, msize * ratio, 0, msize)
GR.setwswindow(0, ratio, 0, 1)
viewport_canvas[1] *= ratio
@@ -638,7 +650,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
end
# Add margin for x and y ticks
xticks, yticks = axis_drawing_info(sp)[1:2]
if !(xticks in (nothing, false))
if !(xticks in (nothing, false, :none))
flip, mirror = gr_set_xticks_font(sp)
l = gr_get_ticks_size(xticks, 2)
if mirror
@@ -647,7 +659,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
bottompad += 1mm + gr_plot_size[2] * l * px
end
end
if !(yticks in (nothing, false))
if !(yticks in (nothing, false, :none))
flip, mirror = gr_set_yticks_font(sp)
l = gr_get_ticks_size(yticks, 1)
if mirror
@@ -780,10 +792,23 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
ztick = GR.tick(zmin, zmax) / 2
ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1])
# GR.setlinetype(GR.LINETYPE_DOTTED)
xaxis[:grid] && GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0)
yaxis[:grid] && GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
zaxis[:grid] && GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2)
if xaxis[:grid]
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
GR.settransparency(xaxis[:gridalpha])
GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0)
end
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
GR.settransparency(yaxis[:gridalpha])
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
end
if zaxis[:grid]
gr_set_line(zaxis[:gridlinewidth], zaxis[:gridstyle], zaxis[:foreground_color_grid])
GR.settransparency(zaxis[:gridalpha])
GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2)
end
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
GR.settransparency(1)
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
@@ -860,9 +885,15 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(cv, sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? ymax : ymin)
# @show cv dv ymin xi yi flip mirror (flip $ mirror)
# ensure correct dispatch in gr_text for automatic log ticks
dv = xaxis[:scale] in (:ln, :log10, :log2) && xaxis[:ticks] == :auto ? string(dv, "\\ ") : string(dv)
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0), dv)
if xaxis[:ticks] in (:auto, :native)
# ensure correct dispatch in gr_text for automatic log ticks
if xaxis[:scale] in _logScales
dv = string(dv, "\\ ")
elseif xaxis[:formatter] == :scientific
dv = convert_sci_unicode(dv)
end
end
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0), string(dv))
end
end
@@ -873,9 +904,15 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? xmax : xmin, cv)
# @show cv dv xmin xi yi
# ensure correct dispatch in gr_text for automatic log ticks
dv = yaxis[:scale] in (:ln, :log10, :log2) && yaxis[:ticks] == :auto ? string(dv, "\\ ") : string(dv)
gr_text(xi + (mirror ? 1 : -1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), yi, dv)
if yaxis[:ticks] in (:auto, :native)
# ensure correct dispatch in gr_text for automatic log ticks
if yaxis[:scale] in _logScales
dv = string(dv, "\\ ")
elseif yaxis[:formatter] == :scientific
dv = convert_sci_unicode(dv)
end
end
gr_text(xi + (mirror ? 1 : -1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), yi, string(dv))
end
end
@@ -977,7 +1014,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
x, y = convert_to_polar(x, y, (rmin, rmax))
end
if st in (:path, :scatter)
if st == :straightline
x, y = straightline_data(series)
end
if st in (:path, :scatter, :straightline)
if length(x) > 1
lz = series[:line_z]
segments_iterator = if lz != nothing && length(lz) > 1
@@ -999,7 +1040,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
# draw the line(s)
if st == :path
if st in (:path, :straightline)
for (i, rng) in enumerate(segments_iterator)
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
@@ -1019,24 +1060,28 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :contour
zmin, zmax = clims
GR.setspace(zmin, zmax, 0, 90)
if typeof(series[:levels]) <: Array
if typeof(series[:levels]) <: AbstractArray
h = series[:levels]
else
h = linspace(zmin, zmax, series[:levels])
h = series[:levels] > 1 ? linspace(zmin, zmax, series[:levels]) : [(zmin + zmax) / 2]
end
if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
else
GR.setlinetype(gr_linetype[series[:linestyle]])
GR.setlinewidth(max(0, series[:linewidth] / (sum(gr_plot_size) * 0.001)))
GR.contour(x, y, h, z, 1000)
if plot_color(series[:linecolor]) == [plot_color(:black)]
GR.contour(x, y, h, z, 0 + (series[:contour_labels] == true ? 1 : 0))
else
GR.contour(x, y, h, z, 1000 + (series[:contour_labels] == true ? 1 : 0))
end
end
# create the colorbar of contour levels
if cmap
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_viewport_cmap(sp)
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
l = (length(h) > 1) ? round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255) : Int32[1000, 1255]
GR.setwindow(xmin, xmax, zmin, zmax)
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
ztick = 0.5 * GR.tick(zmin, zmax)
@@ -1061,7 +1106,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
zmin, zmax = clims
GR.setspace(zmin, zmax, 0, 90)
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
colors = [grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)] for zi=z]
colors = [plot_color(grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)], series[:fillalpha]) for zi=z]
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
round(Int, blue(c) * 255) << 16 +
round(Int, green(c) * 255) << 8 +
@@ -1141,6 +1186,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.selntran(1)
elseif st == :shape
x, y = shape_data(series)
for (i,rng) in enumerate(iter_segments(x, y))
if length(rng) > 1
# connect to the beginning
@@ -1163,8 +1209,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :image
z = transpose_z(series, series[:z].surf, true)'
w, h = size(z)
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
if eltype(z) <: Colors.AbstractGray
grey = round(UInt8, float(z) * 255)
grey = round.(UInt8, float(z) * 255)
rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey)
else
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
@@ -1253,7 +1300,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
st == :shape && gr_polyline(x, y)
end
if st == :path
if st in (:path, :straightline)
GR.settransparency(gr_alpha(series[:linealpha]))
if series[:fillrange] == nothing || series[:ribbon] != nothing
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
@@ -1294,7 +1341,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
end
for ann in sp[:annotations]
x, y, val = ann
x, y, val = locate_annotation(sp, ann...)
x, y = if is3d(sp)
# GR.wc3towc(x, y, z)
else
@@ -1335,7 +1382,7 @@ for (mime, fmt) in _gr_mimeformats
env = get(ENV, "GKSwstype", "0")
ENV["GKSwstype"] = $fmt
ENV["GKS_FILEPATH"] = filepath
gr_display(plt)
gr_display(plt, $fmt)
GR.emergencyclosegks()
write(io, readstring(filepath))
rm(filepath)
+2 -2
View File
@@ -29,7 +29,7 @@ Read from .hdf5 file using:
==#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
end
import FixedPointNumbers: N0f8 #In core Julia
@@ -97,7 +97,7 @@ const _hdf5_attr = merge_with_base_supported([
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape,
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
+8 -3
View File
@@ -57,7 +57,7 @@ const _inspectdr_attr = merge_with_base_supported([
])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [
:path, :scatter, :shape #, :steppre, :steppost
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
]
#see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[
@@ -243,7 +243,11 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
if nothing == plot; return; end
_vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x = _vectorize(series[:x]); y = _vectorize(series[:y])
x, y = if st == :straightline
straightline_data(series)
else
_vectorize(series[:x]), _vectorize(series[:y])
end
#No support for polar grid... but can still perform polar transformation:
if ispolar(sp)
@@ -268,6 +272,7 @@ For st in :shape:
=#
if st in (:shape,)
x, y = shape_data(series)
nmax = 0
for (i,rng) in enumerate(iter_segments(x, y))
nmax = i
@@ -299,7 +304,7 @@ For st in :shape:
color = linecolor, fillcolor = fillcolor
)
end
elseif st in (:path, :scatter) #, :steppre, :steppost)
elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost)
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth:
+14 -5
View File
@@ -39,7 +39,7 @@ const _pgfplots_attr = merge_with_base_supported([
:framestyle,
:camera,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
@@ -220,6 +220,10 @@ function pgf_series(sp::Subplot, series::Series)
d[:z].surf, d[:x], d[:y]
elseif is3d(st)
d[:x], d[:y], d[:z]
elseif st == :straightline
straightline_data(series)
elseif st == :shape
shape_data(series)
elseif d[:marker_z] != nothing
# If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation
@@ -272,6 +276,9 @@ function pgf_axis(sp::Subplot, letter)
style = []
kw = KW()
# turn off scaled ticks
push!(style, "scaled $(letter) ticks = false")
# set to supported framestyle
framestyle = pgf_framestyle(sp[:framestyle])
@@ -292,7 +299,7 @@ function pgf_axis(sp::Subplot, letter)
end
# ticks on or off
if axis[:ticks] in (nothing, false) || framestyle == :none
if axis[:ticks] in (nothing, false, :none) || framestyle == :none
push!(style, "$(letter)majorticks=false")
end
@@ -311,7 +318,7 @@ function pgf_axis(sp::Subplot, letter)
kw[Symbol(letter,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none)) && framestyle != :none
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
ticks = get_ticks(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]
@@ -326,6 +333,7 @@ function pgf_axis(sp::Subplot, letter)
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
elseif axis[:showaxis]
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
tick_labels = axis[:formatter] == :scientific ? string.("\$", convert_sci_unicode.(tick_labels), "\$") : tick_labels
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
else
push!(style, string(letter, "ticklabels = {}"))
@@ -446,7 +454,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
end
@label colorbar_end
o = axisf(; style = style, kw...)
o = axisf(; style = join(style, ","), kw...)
# add the series object to the PGFPlots.Axis
for series in series_list(sp)
@@ -461,7 +469,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# add the annotations
for ann in sp[:annotations]
pgf_add_annotation!(o,ann...)
pgf_add_annotation!(o, locate_annotation(sp, ann...)...)
end
@@ -497,6 +505,7 @@ end
function _display(plt::Plot{PGFPlotsBackend})
# prepare the object
PGFPlots.pushPGFPlotsPreamble("\\usepackage{fontspec}")
pgfplt = PGFPlots.plot(plt.o)
# save an svg
+101 -71
View File
@@ -45,11 +45,13 @@ const _plotly_attr = merge_with_base_supported([
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _plotly_seriestype = [
:path, :scatter, :bar, :pie, :heatmap,
:path, :scatter, :pie, :heatmap,
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
:straightline
]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [
@@ -86,8 +88,6 @@ const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
function _initialize_backend(::PlotlyBackend; kw...)
@eval begin
import JSON
_js_code = open(readstring, _plotly_js_path, "r")
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
@@ -147,7 +147,7 @@ function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
:text => val,
:xref => xref,
:x => x,
:yref => xref,
:yref => yref,
:y => y,
:showarrow => false,
)
@@ -233,7 +233,7 @@ function plotly_domain(sp::Subplot, letter)
end
function plotly_axis(axis::Axis, sp::Subplot)
function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
letter = axis[:letter]
framestyle = sp[:framestyle]
ax = KW(
@@ -253,14 +253,20 @@ function plotly_axis(axis::Axis, sp::Subplot)
if letter in (:x,:y)
ax[:domain] = plotly_domain(sp, letter)
ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))"
if is3d(sp)
# don't link 3d axes for synchronized interactivity
x_idx = y_idx = sp[:subplot_index]
else
x_idx, y_idx = plotly_link_indicies(plt, sp)
end
ax[:anchor] = "$(letter==:x ? "y$(y_idx)" : "x$(x_idx)")"
end
ax[:tickangle] = -axis[:rotation]
lims = axis_limits(axis)
ax[:range] = map(scalefunc(axis[:scale]), lims)
if !(axis[:ticks] in (nothing, :none))
axis[:ticks] != :native ? ax[:range] = map(scalefunc(axis[:scale]), lims) : nothing
if !(axis[:ticks] in (nothing, :none, false))
ax[:titlefont] = plotly_font(guidefont(axis))
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(tickfont(axis))
@@ -273,8 +279,8 @@ function plotly_axis(axis::Axis, sp::Subplot)
end
# ticks
ticks = get_ticks(axis)
if ticks != :auto
if axis[:ticks] != :native
ticks = get_ticks(axis)
ttype = ticksType(ticks)
if ttype == :ticks
ax[:tickmode] = "array"
@@ -289,7 +295,7 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:showgrid] = false
end
ax
end
@@ -320,9 +326,8 @@ function plotly_layout(plt::Plot)
d_out[:annotations] = KW[]
for sp in plt.subplots
spidx = plotly_subplot_index(sp)
spidx = sp[:subplot_index]
x_idx, y_idx = plotly_link_indicies(plt, sp)
# add an annotation for the title... positioned horizontally relative to plotarea,
# but vertically just below the top of the subplot bounding box
if sp[:title] != ""
@@ -350,9 +355,9 @@ function plotly_layout(plt::Plot)
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
d_out[:scene] = KW(
Symbol("xaxis$spidx") => plotly_axis(sp[:xaxis], sp),
Symbol("yaxis$spidx") => plotly_axis(sp[:yaxis], sp),
Symbol("zaxis$spidx") => plotly_axis(sp[:zaxis], sp),
Symbol("xaxis$(spidx)") => plotly_axis(plt, sp[:xaxis], sp),
Symbol("yaxis$(spidx)") => plotly_axis(plt, sp[:yaxis], sp),
Symbol("zaxis$(spidx)") => plotly_axis(plt, sp[:zaxis], sp),
#2.6 multiplier set camera eye such that whole plot can be seen
:camera => KW(
@@ -364,11 +369,12 @@ function plotly_layout(plt::Plot)
),
)
elseif ispolar(sp)
d_out[Symbol("angularaxis$spidx")] = plotly_polaraxis(sp[:xaxis])
d_out[Symbol("radialaxis$spidx")] = plotly_polaraxis(sp[:yaxis])
d_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
d_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
else
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
d_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
# don't allow yaxis to be reupdated/reanchored in a linked subplot
spidx == y_idx ? d_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing
end
# legend
@@ -385,8 +391,9 @@ function plotly_layout(plt::Plot)
end
# annotations
append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]])
for ann in sp[:annotations]
append!(d_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
end
# series_annotations
for series in series_list(sp)
anns = series[:series_annotations]
@@ -394,7 +401,7 @@ function plotly_layout(plt::Plot)
push!(d_out[:annotations], plotly_annotation_dict(
xi,
yi,
PlotText(str,fnt); xref = "x$spidx", yref = "y$spidx")
PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)")
)
end
end
@@ -430,9 +437,17 @@ end
function plotly_colorscale(grad::ColorGradient, α)
[[grad.values[i], rgb_string(grad.colors[i])] for i in 1:length(grad.colors)]
[[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in 1:length(grad.colors)]
end
plotly_colorscale(c, α) = plotly_colorscale(cgrad(alpha=α), α)
function plotly_colorscale(c::AbstractVector{<:RGBA}, α)
if length(c) == 1
return [[0.0, rgba_string(plot_color(c[1], α))], [1.0, rgba_string(plot_color(c[1], α))]]
else
vals = linspace(0.0, 1.0, length(c))
return [[vals[i], rgba_string(plot_color(c[i], α))] for i in eachindex(c)]
end
end
# plotly_colorscale(c, alpha = nothing) = plotly_colorscale(cgrad(), alpha)
@@ -447,9 +462,15 @@ const _plotly_markers = KW(
:hline => "line-ew",
)
function plotly_subplot_index(sp::Subplot)
spidx = sp[:subplot_index]
spidx == 1 ? "" : spidx
# find indicies of axes to which the supblot links to
function plotly_link_indicies(plt::Plot, sp::Subplot)
if plt[:link] in (:x, :y, :both)
x_idx = sp[:xaxis].sps[1][:subplot_index]
y_idx = sp[:yaxis].sps[1][:subplot_index]
else
x_idx = y_idx = sp[:subplot_index]
end
x_idx, y_idx
end
@@ -464,7 +485,7 @@ function plotly_close_shapes(x, y)
nanvcat(xs), nanvcat(ys)
end
plotly_data(v) = collect(v)
plotly_data(v) = v != nothing ? collect(v) : v
plotly_data(surf::Surface) = surf.surf
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
@@ -487,27 +508,33 @@ function plotly_series(plt::Plot, series::Series)
d_out = KW()
# these are the axes that the series should be mapped to
spidx = plotly_subplot_index(sp)
d_out[:xaxis] = "x$spidx"
d_out[:yaxis] = "y$spidx"
x_idx, y_idx = plotly_link_indicies(plt, sp)
d_out[:xaxis] = "x$(x_idx)"
d_out[:yaxis] = "y$(y_idx)"
d_out[:showlegend] = should_add_to_legend(series)
x, y = plotly_data(series[:x]), plotly_data(series[:y])
x, y, z = map(letter -> (axis = sp[Symbol(letter, :axis)];
if axis[:ticks] == :native && !isempty(axis[:discrete_values])
axis[:discrete_values]
elseif st in (:heatmap, :contour, :surface, :wireframe)
plotly_surface_data(series, series[letter])
else
plotly_data(series[letter])
end), (:x, :y, :z))
if st == :straightline
x, y = straightline_data(series)
end
d_out[:name] = series[:label]
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d)
hasfillrange = st in (:path, :scatter, :scattergl) &&
hasline = st in (:path, :path3d, :straightline)
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
# for surface types, set the data
if st in (:heatmap, :contour, :surface, :wireframe)
for letter in [:x,:y,:z]
d_out[letter] = plotly_surface_data(series, series[letter])
end
end
d_out[:colorbar] = KW(:title => sp[:colorbar_title])
clims = sp[:clims]
@@ -516,7 +543,7 @@ function plotly_series(plt::Plot, series::Series)
end
# set the "type"
if st in (:path, :scatter, :scattergl)
if st in (:path, :scatter, :scattergl, :straightline)
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
@@ -526,7 +553,7 @@ function plotly_series(plt::Plot, series::Series)
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
d_out[:fill] = "tozeroy"
d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif isa(series[:fillrange], AbstractVector)
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
d_out[:fill] = "tonexty"
d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif !(series[:fillrange] in (false, nothing))
@@ -534,35 +561,24 @@ function plotly_series(plt::Plot, series::Series)
end
d_out[:x], d_out[:y] = x, y
elseif st == :bar
d_out[:type] = "bar"
d_out[:x], d_out[:y], d_out[:orientation] = if isvertical(series)
x, y, "v"
else
y, x, "h"
end
d_out[:width] = series[:bar_width]
d_out[:marker] = KW(:color => rgba_string(series[:fillcolor]),
:line => KW(:width => series[:linewidth]))
elseif st == :heatmap
d_out[:type] = "heatmap"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:x], d_out[:y], d_out[:z] = x, y, z
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:showscale] = hascolorbar(sp)
elseif st == :contour
d_out[:type] = "contour"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:x], d_out[:y], d_out[:z] = x, y, z
# d_out[:showscale] = series[:colorbar] != :none
d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
d_out[:showscale] = hascolorbar(sp)
elseif st in (:surface, :wireframe)
d_out[:type] = "surface"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:x], d_out[:y], d_out[:z] = x, y, z
if st == :wireframe
d_out[:hidesurface] = true
wirelines = KW(
@@ -594,8 +610,7 @@ function plotly_series(plt::Plot, series::Series)
else
hasline ? "lines" : "none"
end
d_out[:x], d_out[:y] = x, y
d_out[:z] = plotly_data(series[:z])
d_out[:x], d_out[:y], d_out[:z] = x, y, z
else
warn("Plotly: seriestype $st isn't supported.")
@@ -610,14 +625,14 @@ function plotly_series(plt::Plot, series::Series)
:size => 2 * series[:markersize],
# :color => rgba_string(series[:markercolor]),
:line => KW(
:color => rgba_string(series[:markerstrokecolor]),
:color => _cycle(rgba_string.(series[:markerstrokecolor]),eachindex(series[:x])),
:width => series[:markerstrokewidth],
),
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
if series[:marker_z] == nothing
d_out[:marker][:color] = rgba_string(series[:markercolor])
d_out[:marker][:color] = _cycle(rgba_string.(series[:markercolor]),eachindex(series[:x]))
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
# grad = as_gradient(series[:markercolor], series[:markeralpha])
@@ -656,6 +671,14 @@ function plotly_series(plt::Plot, series::Series)
# series, one for series being filled to) instead of one
d_out_fillrange = deepcopy(d_out)
d_out_fillrange[:showlegend] = false
# if fillrange is provided as real or tuple of real, expand to array
if typeof(series[:fillrange]) <: Real
series[:fillrange] = fill(series[:fillrange], length(series[:x]))
elseif typeof(series[:fillrange]) <: Tuple
f1 = typeof(series[:fillrange][1]) <: Real ? fill(series[:fillrange][1], length(series[:x])) : series[:fillrange][1]
f2 = typeof(series[:fillrange][2]) <: Real ? fill(series[:fillrange][2], length(series[:x])) : series[:fillrange][2]
series[:fillrange] = (f1, f2)
end
if isa(series[:fillrange], AbstractVector)
d_out_fillrange[:y] = series[:fillrange]
delete!(d_out_fillrange, :fill)
@@ -683,14 +706,14 @@ function plotly_series_shapes(plt::Plot, series::Series)
# x, y = series[:x], series[:y]
# these are the axes that the series should be mapped to
spidx = plotly_subplot_index(series[:subplot])
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
base_d = KW()
base_d[:xaxis] = "x$spidx"
base_d[:yaxis] = "y$spidx"
base_d[:xaxis] = "x$(x_idx)"
base_d[:yaxis] = "y$(y_idx)"
base_d[:name] = series[:label]
# base_d[:legendgroup] = series[:label]
x, y = plotly_data(series[:x]), plotly_data(series[:y])
x, y = shape_data(series)
for (i,rng) in enumerate(iter_segments(x,y))
length(rng) < 2 && continue
@@ -738,15 +761,17 @@ function plotly_hover!(d_out::KW, hover)
end
# get a list of dictionaries, each representing the series params
function plotly_series_json(plt::Plot)
function plotly_series(plt::Plot)
slist = []
for series in plt.series_list
append!(slist, plotly_series(plt, series))
end
JSON.json(slist)
# JSON.json(map(series -> plotly_series(plt, series), plt.series_list))
slist
end
# get json string for a list of dictionaries, each representing the series params
plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt))
# ----------------------------------------------------------------
const _use_remote = Ref(false)
@@ -793,6 +818,11 @@ function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend})
write(io, html_head(plt) * html_body(plt))
end
function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
prepare_output(plt)
write(io, html_head(plt) * html_body(plt))
end
function _display(plt::Plot{PlotlyBackend})
standalone_html_window(plt)
end
+38 -15
View File
@@ -42,9 +42,10 @@ const _pyplot_attr = merge_with_base_supported([
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape,
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
@@ -92,7 +93,7 @@ function _initialize_backend(::PyPlotBackend)
pynp["seterr"](invalid="ignore")
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
const pycollections = PyPlot.pyimport("matplotlib.collections")
const pyart3d = PyPlot.pyimport("mpl_toolkits.mplot3d.art3d")
const pyart3d = PyPlot.art3D
# "support" matplotlib v1.5
const set_facecolor_sym = if PyPlot.version < v"2"
@@ -215,6 +216,8 @@ function py_marker(marker::Symbol)
marker == :hexagon && return "h"
marker == :octagon && return "8"
marker == :pixel && return ","
marker == :hline && return "_"
marker == :vline && return "|"
haskey(_shapes, marker) && return py_marker(_shapes[marker])
warn("Unknown marker $marker")
@@ -450,6 +453,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# ax = getAxis(plt, series)
x, y, z = series[:x], series[:y], series[:z]
if st == :straightline
x, y = straightline_data(series)
elseif st == :shape
x, y = shape_data(series)
end
xyargs = (st in _3dTypes ? (x,y,z) : (x,y))
# handle zcolor and get c/cmap
@@ -483,7 +491,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# for each plotting command, optionally build and add a series handle to the list
# line plot
if st in (:path, :path3d, :steppre, :steppost)
if st in (:path, :path3d, :steppre, :steppost, :straightline)
if series[:linewidth] > 0
if series[:line_z] == nothing
handle = ax[:plot](xyargs...;
@@ -572,7 +580,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
:scatter3d, :steppre, :steppost,
:bar)
if series[:marker_z] == nothing
extrakw[:c] = py_color_fix(py_markercolor(series), x)
extrakw[:c] = series[:markershape] in (:+, :x, :hline, :vline) ? py_markerstrokecolor(series) : py_color_fix(py_markercolor(series), x)
else
extrakw[:c] = convert(Vector{Float64}, series[:marker_z])
extrakw[:cmap] = py_markercolormap(series)
@@ -644,15 +652,23 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw[:extend3d] = true
end
if typeof(series[:linecolor]) <: AbstractArray
extrakw[:colors] = py_color.(series[:linecolor])
else
extrakw[:cmap] = py_linecolormap(series)
end
# contour lines
handle = ax[:contour](x, y, z, levelargs...;
label = series[:label],
zorder = series[:series_plotindex],
linewidths = py_dpi_scale(plt, series[:linewidth]),
linestyles = py_linestyle(st, series[:linestyle]),
cmap = py_linecolormap(series),
extrakw...
)
if series[:contour_labels] == true
PyPlot.clabel(handle, handle[:levels])
end
push!(handles, handle)
# contour fills
@@ -660,7 +676,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
handle = ax[:contourf](x, y, z, levelargs...;
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
cmap = py_fillcolormap(series),
extrakw...
)
push!(handles, handle)
@@ -732,11 +747,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if st == :image
# @show typeof(z)
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
img = Array(transpose_z(series, z.surf))
z = if eltype(img) <: Colors.AbstractGray
float(img)
elseif eltype(img) <: Colorant
map(c -> Float64[red(c),green(c),blue(c)], img)
map(c -> Float64[red(c),green(c),blue(c),alpha(c)], img)
else
z # hopefully it's in a data format that will "just work" with imshow
end
@@ -744,7 +760,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
zorder = series[:series_plotindex],
cmap = py_colormap([:black, :white]),
vmin = 0.0,
vmax = 1.0
vmax = 1.0,
extent = (xmin, xmax, ymax, ymin)
)
push!(handles, handle)
@@ -768,6 +785,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
label = series[:label],
zorder = series[:series_plotindex],
cmap = py_fillcolormap(series),
alpha = series[:fillalpha],
# edgecolors = (series[:linewidth] > 0 ? py_linecolor(series) : "face"),
extrakw...
)
@@ -968,7 +986,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
# add the annotations
for ann in sp[:annotations]
py_add_annotations(sp, ann...)
py_add_annotations(sp, locate_annotation(sp, ann...)...)
end
# title
@@ -1058,7 +1076,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
pyaxis[Symbol(:tick_, pos)]() # the tick labels
end
py_set_scale(ax, axis)
py_set_lims(ax, axis)
axis[:ticks] != :native ? py_set_lims(ax, axis) : nothing
if ispolar(sp) && letter == :y
ax[:set_rlabel_position](90)
end
@@ -1067,7 +1085,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if sp[:framestyle] == :origin && length(ticks) > 1
ticks[2][ticks[1] .== 0] = ""
end
py_set_ticks(ax, ticks, letter)
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
ax[Symbol("set_", letter, "label")](axis[:guide])
if get(axis.d, :flip, false)
@@ -1137,6 +1155,10 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
# this sets the bg color inside the grid
ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
# link axes
x_ax_link, y_ax_link = sp[:xaxis].sps[1].o, sp[:yaxis].sps[1].o
ax != x_ax_link && ax[:get_shared_x_axes]()[:join](ax, sp[:xaxis].sps[1].o)
ax != y_ax_link && ax[:get_shared_y_axes]()[:join](ax, sp[:yaxis].sps[1].o)
end
py_drawfig(fig)
end
@@ -1232,14 +1254,14 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
facecolor = py_color(_cycle(series[:fillcolor],1)),
linewidth = py_dpi_scale(plt, clamp(series[:linewidth], 0, 5)),
)
elseif series[:seriestype] == :path
elseif series[:seriestype] in (:path, :straightline)
PyPlot.plt[:Line2D]((0,1),(0,0),
color = py_color(_cycle(series[:fillcolor],1)),
color = py_color(_cycle(series[:linecolor],1)),
linewidth = py_dpi_scale(plt, clamp(series[:linewidth], 0, 5)),
linestyle = py_linestyle(:path,series[:linestyle]),
marker = py_marker(series[:markershape]),
markeredgecolor = py_markerstrokecolor(series),
markerfacecolor = py_markercolor(series)
markerfacecolor = series[:marker_z] == nothing ? py_markercolor(series) : py_color(series[:markercolor][0.5])
)
else
series[:serieshandle][1]
@@ -1293,7 +1315,8 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
if haskey(sp.attr, :cbar_ax)
cbw = sp.attr[:cbar_width]
# this is the bounding box of just the colors of the colorbar (not labels)
has_toplabel = sp[:zaxis][:extrema].emax >= 1e7
ex = sp[:zaxis][:extrema]
has_toplabel = !(1e-7 < max(abs(ex.emax), abs(ex.emin)) < 1e7)
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox) + (has_toplabel ? 4mm : 2mm), _cbar_width-1mm, height(sp.bbox) - (has_toplabel ? 6mm : 4mm))
pcts = bbox_to_pcts(cb_bbox, figw, figh)
sp.attr[:cbar_ax][:set_position](pcts)
+11 -5
View File
@@ -2,7 +2,7 @@
# https://github.com/Evizero/UnicodePlots.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
end
const _unicodeplots_attr = merge_with_base_supported([
@@ -17,7 +17,7 @@ const _unicodeplots_attr = merge_with_base_supported([
:guide, :lims,
])
const _unicodeplots_seriestype = [
:path, :scatter,
:path, :scatter, :straightline,
# :bar,
:shape,
:histogram2d,
@@ -142,7 +142,7 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
return
end
if st == :path
if st in (:path, :straightline)
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
@@ -155,14 +155,20 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
end
# get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
x, y = if st == :straightline
straightline_data(d)
elseif st == :shape
shape_data(series)
else
[collect(float(d[s])) for s in (:x, :y)]
end
label = addlegend ? d[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
# add the series
x, y = Plots.unzip(collect(filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
x, y = Plots.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
func(o, x, y; color = color, name = label)
end
+49
View File
@@ -348,6 +348,7 @@ PlotText(str) = PlotText(string(str), font())
Create a PlotText object wrapping a string with font info, for plot annotations
"""
text(t::PlotText) = t
text(t::PlotText, font::Font) = PlotText(t.str, font)
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
PlotText(string(str), font(args...))
@@ -535,6 +536,54 @@ annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
annotations(sa::SeriesAnnotations) = sa
# Expand arrays of coordinates, positions and labels into induvidual annotations
# and make sure labels are of type PlotText
function process_annotation(sp::Subplot, xs, ys, labs, font = font())
anns = []
labs = makevec(labs)
for i in 1:max(length(xs), length(ys), length(labs))
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (x, y, isa(lab, PlotText) ? lab : text(lab, font)))
end
end
anns
end
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font())
anns = []
positions, labs = makevec(positions), makevec(labs)
for i in 1:max(length(positions), length(labs))
pos, lab = _cycle(positions, i), _cycle(labs, i)
pos = get(_positionAliases, pos, pos)
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font)))
end
end
anns
end
# Give each annotation coordinates based on specified position
function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}(
:topleft => (0.1, 0.9),
:topcenter => (0.5, 0.9),
:topright => (0.9, 0.9),
:bottomleft => (0.1, 0.1),
:bottomcenter => (0.5, 0.1),
:bottomright => (0.9, 0.1),
)
xmin, xmax = ignorenan_extrema(sp[:xaxis])
ymin, ymax = ignorenan_extrema(sp[:yaxis])
x, y = (xmin, ymin).+ position_multiplier[pos].* (xmax - xmin, ymax - ymin)
(x, y, lab)
end
locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label)
# -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)"
+42 -11
View File
@@ -171,7 +171,9 @@ const _mimeformats = Dict(
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
:glvisualize => :png
:glvisualize => :png,
:plotlyjs => :html,
:plotly => :html
)
# a backup for html... passes to svg or png depending on the html_output_format arg
@@ -256,20 +258,50 @@ end
# IJulia
# ---------------------------------------------------------
const _ijulia_output = String["text/html"]
@require IJulia begin
if IJulia.inited
export set_ijulia_output
function set_ijulia_output(mimestr::AbstractString)
# info("Setting IJulia output format to $mimestr")
global _ijulia_output
_ijulia_output[1] = mimestr
"""
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)
global _ijulia_output
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
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 == :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
# default text/plain passes to html... handles Interact issues
@@ -278,7 +310,6 @@ const _ijulia_output = String["text/html"]
end
ENV["MPLBACKEND"] = "Agg"
set_ijulia_output("text/html")
end
end
+3 -4
View File
@@ -357,10 +357,9 @@ end
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
# adjust extrema and discrete info
if st == :image
w, h = size(d[:z])
expand_extrema!(sp[:xaxis], (0,w))
expand_extrema!(sp[:yaxis], (0,h))
sp[:yaxis].d[:flip] = true
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
expand_extrema!(sp[:xaxis], (xmin, xmax))
expand_extrema!(sp[:yaxis], (ymin, ymax))
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
expand_extrema!(sp, d)
end
+6 -4
View File
@@ -102,8 +102,13 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
end
end
# create the layout and initialize the subplots
# create the layout
plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts))
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# initialize the subplots
cmdidx = 1
for (idx, sp) in enumerate(plt.subplots)
_initialize_subplot(plt, sp)
@@ -127,9 +132,6 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
_update_subplot_args(plt, sp, d, idx, false)
end
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# finish up
current(plt)
_do_plot_show(plt, get(d, :show, default(:show)))
+59 -26
View File
@@ -79,28 +79,50 @@ function hvline_limits(axis::Axis)
end
@recipe function f(::Type{Val{:hline}}, x, y, z)
xmin, xmax = hvline_limits(plotattributes[:subplot][:xaxis])
n = length(y)
newx = repmat(Float64[xmin, xmax, NaN], n)
newx = repmat(Float64[-1, 1, NaN], n)
newy = vec(Float64[yi for i=1:3,yi=y])
x := newx
y := newy
seriestype := :path
seriestype := :straightline
()
end
@deps hline path
@deps hline straightline
@recipe function f(::Type{Val{:vline}}, x, y, z)
ymin, ymax = hvline_limits(plotattributes[:subplot][:yaxis])
n = length(y)
newx = vec(Float64[yi for i=1:3,yi=y])
newy = repmat(Float64[ymin, ymax, NaN], n)
newy = repmat(Float64[-1, 1, NaN], n)
x := newx
y := newy
seriestype := :path
seriestype := :straightline
()
end
@deps vline path
@deps vline straightline
@recipe function f(::Type{Val{:hspan}}, x, y, z)
n = div(length(y), 2)
newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
newy = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...)
linewidth --> 0
x := newx
y := newy
seriestype := :shape
()
end
@deps hspan shape
@recipe function f(::Type{Val{:vspan}}, x, y, z)
n = div(length(y), 2)
newx = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...)
newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
linewidth --> 0
x := newx
y := newy
seriestype := :shape
()
end
@deps vspan shape
# ---------------------------------------------------------------------------
# path and scatter
@@ -124,27 +146,32 @@ end
# ---------------------------------------------------------------------------
# steps
function make_steps(x, y, st)
make_steps(x, st) = x
function make_steps(x::AbstractArray, st)
n = length(x)
n == 0 && return zeros(0),zeros(0)
newx, newy = zeros(2n-1), zeros(2n-1)
for i=1:n
idx = 2i-1
n == 0 && return zeros(0)
newx = zeros(2n - 1)
for i in 1:n
idx = 2i - 1
newx[idx] = x[i]
newy[idx] = y[i]
if i > 1
newx[idx-1] = x[st == :steppre ? i-1 : i]
newy[idx-1] = y[st == :steppre ? i : i-1]
newx[idx - 1] = x[st == :pre ? i : i - 1]
end
end
newx, newy
return newx
end
make_steps(t::Tuple, st) = Tuple(make_steps(ti, st) for ti in t)
# create a path from steps
@recipe function f(::Type{Val{:steppre}}, x, y, z)
plotattributes[:x], plotattributes[:y] = make_steps(x, y, :steppre)
plotattributes[:x] = make_steps(x, :post)
plotattributes[:y] = make_steps(y, :pre)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre)
# create a secondary series for the markers
if plotattributes[:markershape] != :none
@series begin
@@ -163,9 +190,13 @@ end
# create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z)
plotattributes[:x], plotattributes[:y] = make_steps(x, y, :steppost)
plotattributes[:x] = make_steps(x, :pre)
plotattributes[:y] = make_steps(y, :post)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post)
# create a secondary series for the markers
if plotattributes[:markershape] != :none
@series begin
@@ -308,7 +339,11 @@ end
# compute half-width of bars
bw = plotattributes[:bar_width]
hw = if bw == nothing
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx)))
if nx > 1
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx)))
else
0.5 * _bar_width
end
else
Float64[0.5_cycle(bw,i) for i=1:length(procx)]
end
@@ -986,23 +1021,21 @@ end
# -------------------------------------------------
"Adds a+bx... straight line over the current plot, without changing the axis limits"
function abline!(plt::Plot, a, b; kw...)
xl, yl = xlims(plt), ylims(plt)
x1, x2 = max(xl[1], (yl[1] - b)/a), min(xl[2], (yl[2] - b)/a)
plot!(plt, x -> b + a*x, x1, x2; kw...)
end
abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...)
abline!(args...; kw...) = abline!(current(), args...; kw...)
# -------------------------------------------------
# Dates
# Dates & Times
dateformatter(dt) = string(Date(Dates.UTD(dt)))
datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
@recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter)
# -------------------------------------------------
# Complex Numbers
+42 -1
View File
@@ -46,7 +46,7 @@ convertToAnyVector(v::Volume, d::KW) = Any[v], nothing
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# # dates
# convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
@@ -321,10 +321,12 @@ end
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
end
@@ -337,10 +339,12 @@ end
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, 1:m, 1:n, Surface(z)
end
@@ -465,6 +469,38 @@ end
SliceIt, x, y, Surface(z)
end
# # images - grays
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Gray
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, x, y, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, x, y, Surface(convert(Matrix{Float64}, mat))
end
end
# # images - colors
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Colorant
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, x, y, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, x, y, Surface(z)
end
end
#
#
# # --------------------------------------------------------------------
@@ -548,9 +584,14 @@ end
splittable_kw(key, val, lengthGroup) = false
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup)
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val)-1)...]
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
function split_kw(key, val::SeriesAnnotations, indices)
split_strs = split_kw(key, val.strs, indices)
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor)
end
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
+4 -5
View File
@@ -77,15 +77,16 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
defaults = _get_defaults(thm)
# get the gradient
gradient_colors = pop!(defaults, :gradient, cgrad(:inferno).colors)
gradient_colors = get(defaults, :gradient, cgrad(:inferno).colors)
gradient = cgrad(cfunc.(RGB.(gradient_colors)))
# get the palette
palette = pop!(defaults, :palette, get_color_palette(:auto, plot_color(:white), 17))
palette = get(defaults, :palette, get_color_palette(:auto, plot_color(:white), 17))
palette = cfunc.(RGB.(palette))
# apply the theme
for k in keys(defaults)
k in (:gradient, :palette) && continue
def = defaults[k]
arg = get(_keyAliases, k, k)
plotattributes[arg] = if typeof(def) <: Colorant
@@ -110,7 +111,6 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 1
palette := palette
seriestype := :path
linewidth := 2
cumsum(randn(50))
end
@@ -118,8 +118,6 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 2
seriestype := :scatter
palette := palette
markersize := 5
markerstrokewidth := 0
marker := (:circle, :diamond, :star5, :square)[j]
randn(10), randn(10)
end
@@ -142,6 +140,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 4
seriestype := :heatmap
seriescolor := gradient
ticks := -5:5:5
x, y, z
end
+107 -4
View File
@@ -199,7 +199,7 @@ allnan(istart::Int, iend::Int, args::Tuple) = all(i -> anynan(i, args), istart:i
function Base.start(itr::SegmentsIterator)
nextidx = 1
if anynan(1, itr.args)
if !any(isempty,itr.args) && anynan(1, itr.args)
_, nextidx = next(itr, 1)
end
nextidx
@@ -553,8 +553,9 @@ zlims(sp_idx::Int = 1) = zlims(current(), sp_idx)
function get_clims(sp::Subplot)
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface)
for series in series_list(sp)
for vals in (series[:z], series[:line_z], series[:marker_z], series[:fill_z])
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Real)
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals.surf)...)
elseif (vals != nothing) && (eltype(vals) <: Real)
@@ -567,14 +568,17 @@ function get_clims(sp::Subplot)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
return zmin < zmax ? (zmin, zmax) : (0.0, 0.0)
return zmin < zmax ? (zmin, zmax) : (-0.1, 0.1)
end
_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax)
function hascolorbar(series::Series)
st = series[:seriestype]
hascbar = st in (:heatmap, :contour)
hascbar = st == :heatmap
if st == :contour
hascbar = (isscalar(series[:levels]) ? (series[:levels] > 1) : (length(series[:levels]) > 1)) && (length(unique(Array(series[:z]))) > 1)
end
if series[:marker_z] != nothing || series[:line_z] != nothing || series[:fill_z] != nothing
hascbar = true
end
@@ -1047,3 +1051,102 @@ guidefont(ax::Axis) = font(
ax[:guidefontrotation],
ax[:guidefontcolor],
)
# ---------------------------------------------------------------
# converts unicode scientific notation unsupported by pgfplots and gr
# into a format that works
function convert_sci_unicode(label::AbstractString)
unicode_dict = Dict(
'⁰' => "0",
'¹' => "1",
'²' => "2",
'³' => "3",
'⁴' => "4",
'⁵' => "5",
'⁶' => "6",
'⁷' => "7",
'⁸' => "8",
'⁹' => "9",
'⁻' => "-",
"×10" => "×10^{",
)
for key in keys(unicode_dict)
label = replace(label, key, unicode_dict[key])
end
if contains(label, "10^{")
label = string(label, "}")
end
label
end
function straightline_data(series)
sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))
x, y = series[:x], series[:y]
n = length(x)
if n == 2
return straightline_data(xl, yl, x, y)
else
k, r = divrem(n, 3)
if r == 0
xdata, ydata = fill(NaN, n), fill(NaN, n)
for i in 1:k
inds = (3 * i - 2):(3 * i - 1)
xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds])
end
return xdata, ydata
else
error("Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n")
end
end
end
function straightline_data(xl, yl, x, y)
x_vals, y_vals = if y[1] == y[2]
if x[1] == x[2]
error("Two identical points cannot be used to describe a straight line.")
else
[xl[1], xl[2]], [y[1], y[2]]
end
elseif x[1] == x[2]
[x[1], x[2]], [yl[1], yl[2]]
else
# get a and b from the line y = a * x + b through the points given by
# the coordinates x and x
b = y[1] - (y[1] - y[2]) * x[1] / (x[1] - x[2])
a = (y[1] - y[2]) / (x[1] - x[2])
# get the data values
xdata = [clamp(x[1] + (x[1] - x[2]) * (ylim - y[1]) / (y[1] - y[2]), xl...) for ylim in yl]
xdata, a .* xdata .+ b
end
# expand the data outside the axis limits, by a certain factor too improve
# plotly(js) and interactive behaviour
factor = 100
x_vals = x_vals .+ (x_vals[2] - x_vals[1]) .* factor .* [-1, 1]
y_vals = y_vals .+ (y_vals[2] - y_vals[1]) .* factor .* [-1, 1]
return x_vals, y_vals
end
function shape_data(series)
sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))
x, y = series[:x], series[:y]
factor = 100
for i in eachindex(x)
if x[i] == -Inf
x[i] = xl[1] - factor * (xl[2] - xl[1])
elseif x[i] == Inf
x[i] = xl[2] + factor * (xl[2] - xl[1])
end
end
for i in eachindex(y)
if y[i] == -Inf
y[i] = yl[1] - factor * (yl[2] - yl[1])
elseif y[i] == Inf
y[i] = yl[2] + factor * (yl[2] - yl[1])
end
end
return x, y
end
+1 -1
View File
@@ -23,7 +23,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.13.1"
const _current_plots_version = v"0.16.0"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
+1
View File
@@ -8,6 +8,7 @@ default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()