Compare commits

...

214 Commits

Author SHA1 Message Date
Michael K. Borregaard 531a38bc39 no prec 2017-10-05 12:28:52 +02:00
Michael K. Borregaard 77fa5454e2 remember backticks 2017-10-05 12:27:51 +02:00
Michael Krabbe Borregaard 0cd382a1ce Merge pull request #1129 from mkborregaard/fix-function-vector
Apply automatic limits for vectors of functions
2017-10-05 12:26:04 +02:00
Michael K. Borregaard 9fc0c98722 precompile 2017-10-05 12:25:04 +02:00
Michael Krabbe Borregaard af23074820 Merge pull request #1134 from mkborregaard/patch-release
ready for release
2017-10-05 12:22:52 +02:00
Michael K. Borregaard fdf2d5b20b ready for release 2017-10-05 12:22:12 +02:00
Michael K. Borregaard b37f2141a1 Also import px and pct into PlotMeasures
Necessary for example 29 to work
2017-10-05 12:12:54 +02:00
Michael K. Borregaard 5567038cec simplify 2017-10-04 11:47:20 +02:00
Michael K. Borregaard 0327c9101e slight refactor for clarity 2017-10-04 11:44:20 +02:00
Michael K. Borregaard 3d86d5f530 Apply automatic limits for vectors of functions 2017-10-04 11:38:32 +02:00
Michael K. Borregaard 073724a84c reactivate 2017-10-03 15:14:10 +02:00
Michael Krabbe Borregaard 6a129bfe92 Merge pull request #1128 from mkborregaard/hotfix-measures
Make Measures available in Plots in general too
2017-10-03 15:12:27 +02:00
Michael K. Borregaard 53a4c36aab Make Measures available in Plots in general too 2017-10-03 15:12:01 +02:00
Michael Krabbe Borregaard eb36f4eca0 Merge pull request #1127 from mkborregaard/release-13
Reactivate precompilation
2017-10-03 10:31:29 +02:00
Michael K. Borregaard 54838d386d Reactivate precompilation 2017-10-03 10:31:05 +02:00
Michael Krabbe Borregaard 0235821f24 Merge pull request #1126 from mkborregaard/release-13
release-0.13
2017-10-03 10:29:39 +02:00
Michael K. Borregaard efd116ec52 deactivate precompilation 2017-10-03 10:29:06 +02:00
Michael K. Borregaard ff0f1c5c50 update news.md 2017-10-03 10:28:54 +02:00
Michael Krabbe Borregaard 6bbb26d2ea Merge pull request #855 from mkborregaard/submodule-measure
Add submodule PlotMeasures (fix #821)
2017-10-02 15:20:41 +02:00
Michael K. Borregaard 2a1140c0b3 include PlotMeasures in example 29 2017-10-02 15:07:16 +02:00
Michael Krabbe Borregaard a80c7ada27 Merge pull request #1116 from jw3126/replaceD
replace d by plotattributes inside recipes
2017-10-02 14:46:11 +02:00
Michael Krabbe Borregaard 9bc6d0c7d1 Merge pull request #1122 from mkborregaard/bar_width_fix
Fix barwidth to minimum(diff) not mean(diff)
2017-10-02 11:16:25 +02:00
Michael K. Borregaard f3566a4933 sort before taking diff 2017-10-02 10:02:39 +02:00
Michael K. Borregaard cd958a6c68 Fix barwidth to minimum(diff) not mean(diff) 2017-10-02 08:53:41 +02:00
Michael K. Borregaard 4f6a920f72 Import Measures into Plots 2017-10-02 08:28:25 +02:00
Michael K. Borregaard b717cf1dc0 Rename submodule to PlotMeasures 2017-10-02 08:24:59 +02:00
Michael K. Borregaard 33e5a51a28 add submodule Measure 2017-10-02 07:59:04 +02:00
Josef Heinen dca5a7ce4d Merge pull request #1119 from apalugniok/master
Change GR default 3D view angles
2017-10-01 12:50:51 +02:00
apalugniok bf4dd78a7d Change GR default 3D view angles to match PyPlot 2017-10-01 10:29:44 +01:00
Jan Weidner 489e484117 bump required RecipesBase to 0.2.3 2017-09-29 23:24:58 +02:00
Jan Weidner 6e1cc8449b replace d by plotattributes inside recipes 2017-09-29 23:09:34 +02:00
Michael Krabbe Borregaard bcc2f089be Merge pull request #1115 from mkborregaard/default-function-limits
Function default x limits: fix #1109
2017-09-29 09:44:54 +02:00
Michael K. Borregaard 07843c00d3 Add negative ranges 2017-09-29 09:18:20 +02:00
Daniel Schwabeneder de12915eba Merge pull request #1112 from daschw/tick-orientation
Implement new tick_direction attribute for GR, Plotly(JS), PyPlot, GLVisualize and PGFPlots
2017-09-29 09:08:52 +02:00
Michael K. Borregaard 4395718e0c Try to find default x axis limits where function is defined 2017-09-29 08:58:54 +02:00
Michael Krabbe Borregaard 913fdf5247 Merge pull request #1114 from mkborregaard/fix-1113
Don't delete attr when `plot(::Plot)` - fix #1113
2017-09-29 08:34:44 +02:00
Michael K. Borregaard 650c1730c9 Don't delete attr when plot(::Plot) - fix #1113 2017-09-28 23:32:25 +02:00
Daniel Schwabeneder fba1c66499 Merge pull request #1110 from daschw/line_z
RFC: Implement line_z and fill_z for GR
2017-09-28 00:12:12 +02:00
Daniel Schwabeneder 1c04823877 reset tick size for gr and glvisualize 2017-09-28 00:07:58 +02:00
Daniel Schwabeneder 6c84624d71 fix pgfplots 2017-09-27 23:22:55 +02:00
Daniel Schwabeneder 69fa9e7b10 implement tick_direction for PGFPlots 2017-09-27 17:07:09 +02:00
Daniel Schwabeneder 350237a774 add tick_direction to supported arguments 2017-09-27 13:56:12 +02:00
Daniel Schwabeneder b73ea55bbd implement tick_direction for GR, PyPlot, Plotly and GLVisualize 2017-09-27 13:53:06 +02:00
Daniel Schwabeneder 9eac6a1db0 fix fillalpha 2017-09-26 17:40:54 +02:00
Daniel Schwabeneder ea6ab46a13 fix fill_z for shapes (draw colorbar once) 2017-09-26 17:18:35 +02:00
Daniel Schwabeneder 5f84865365 implement fill_z and line_z for GR 2017-09-26 16:58:46 +02:00
Daniel Schwabeneder 337a107168 different colors for different line segments in GR 2017-09-25 17:22:13 +02:00
Daniel Schwabeneder a7485cc7f5 Merge pull request #1105 from daschw/plot-empty-any
Allow plotting empty Vector{Any} (fix #1078)
2017-09-25 09:57:23 +02:00
Daniel Schwabeneder 8b4edae358 implement line_z for GR 2017-09-24 20:52:02 +02:00
Daniel Schwabeneder b6dca5e9b1 Allow plotting empty Vector{Any} 2017-09-22 20:27:16 +02:00
Daniel Schwabeneder 371f0a6a73 Merge pull request #1092 from daschw/plotly-marker_z
fix marker_z for plotly
2017-09-21 22:04:16 +02:00
Michael Krabbe Borregaard b777a2d3c8 Merge pull request #1096 from fedxa/fix_logscale
Fix for wrong setting of logscale for values below 1e-16
2017-09-20 07:46:16 +02:00
Fedor Bezrukov bdfc4636f0 Fix for wrong setting of logscale for values below 1e-16 2017-09-19 23:22:36 +01:00
Daniel Schwabeneder 7ba128db71 fix marker_z for plotly 2017-09-17 19:14:44 +02:00
Daniel Schwabeneder 0f1d8478ce Merge pull request #1089 from daschw/pyplot-colorbar
activate clims for inactive colorbar in pyplot
2017-09-15 20:04:57 +02:00
Daniel Schwabeneder 9eae2ad76b remove unnecessary setting of needs_colorbar 2017-09-15 18:42:38 +02:00
Daniel Schwabeneder f43f2956f5 activate clims for inactive colorbar 2017-09-15 18:39:56 +02:00
Daniel Schwabeneder 2dc03cc537 Merge pull request #1084 from daschw/pyplot-marker_z
Only one colorbar per subplot on pyplot
2017-09-13 09:17:36 +02:00
Michael Krabbe Borregaard 233b0d0de2 Merge pull request #1086 from anriseth/writemimefix
Use show instead of writemime for eps
2017-09-13 00:09:14 +02:00
Asbjørn Nilsen Riseth dc9a044141 Use show instead of writemime for eps 2017-09-12 16:08:32 +01:00
Daniel Schwabeneder 518fba759f only one colorbar per subplot in pyplot 2017-09-09 11:21:39 +02:00
Daniel Schwabeneder 7dfa1ec984 make GR use hascolorbar 2017-09-09 10:05:58 +02:00
Daniel Schwabeneder da5a538f89 Merge pull request #1083 from daschw/gr-marker_z
Fix GR marker_z and clims (fix #1063)
2017-09-09 09:36:06 +02:00
Daniel Schwabeneder a518796736 reset runtests accuracy 2017-09-08 23:38:43 +02:00
Daniel Schwabeneder 13111b3779 fix marker_z for GR 2017-09-08 22:50:25 +02:00
Michael Krabbe Borregaard 8412d77067 Merge pull request #1082 from timholy/teh/nbins
histogram: ensure the number of bins is finite
2017-09-08 10:25:23 +02:00
Tim Holy fe0ea168f3 histogram: ensure the number of bins is finite 2017-09-08 03:18:46 -05:00
Daniel Schwabeneder af9d97d561 Merge pull request #1077 from daschw/seriestype-error
improve recipe error
2017-09-07 13:29:09 +02:00
Daniel Schwabeneder 478f5b6e20 Merge pull request #1079 from daschw/framestyle
implement framestyles for plotly(js) (fix #1075)
2017-09-07 13:28:43 +02:00
Daniel Schwabeneder c89b125b9a implement framestyles for plotly(js) 2017-09-06 19:09:52 +02:00
Daniel Schwabeneder a981dc71f9 Merge pull request #1057 from daschw/framestyle
RFC: Add :origin framestyle
2017-09-06 16:34:31 +02:00
Daniel Schwabeneder 331dd49326 improve recipe error 2017-09-06 16:03:39 +02:00
Michael Krabbe Borregaard b69c37f1bb Merge pull request #1073 from mkborregaard/fix-2dhistogram-bins
fix 2dhistogram bins
2017-09-06 10:15:03 +02:00
Michael K. Borregaard 20ef846c38 move bracket in Sturges 2017-09-05 22:42:05 +02:00
Michael K. Borregaard cd9f00300c Add correction for correlations 2017-09-05 16:02:52 +02:00
Michael K. Borregaard d6e5b57a08 fix-2dhistogram-bins 2017-09-05 14:01:59 +02:00
Pietro Vertechi d5e5d81ee2 Merge pull request #1062 from piever/groupedbar
WIP: allow to group user recipes
2017-09-05 08:53:26 +01:00
Pietro Vertechi dee24e6f08 add kw support 2017-09-04 12:29:10 +01:00
Michael K. Borregaard 9a2a54b885 reactivate precompilation on master 2017-09-04 13:09:37 +02:00
Michael K. Borregaard 4c2b01ccb0 change version number for testing 2017-09-04 12:18:10 +02:00
Michael Krabbe Borregaard ddf4136022 Merge pull request #1070 from JuliaPlots/release-0.12.4
Release 0.12.4
2017-09-04 12:05:07 +02:00
Michael K. Borregaard 4f8fc61689 Turn off precompile for release 2017-09-04 12:02:34 +02:00
Michael K. Borregaard c8a7a050de Update News.md with 12.4 improvements 2017-09-04 12:02:19 +02:00
Michael Krabbe Borregaard fb04b3d78b Merge pull request #1069 from daschw/seriestype-error
Seriestype error (fix #1068)
2017-09-04 11:50:17 +02:00
Pietro Vertechi 0f28b59c5f added support for 1 or 3 arguments to group as matrix 2017-09-04 10:24:43 +01:00
Pietro Vertechi e2795341d9 moved group_as_matrix to Plots 2017-09-04 09:48:49 +01:00
Michael Krabbe Borregaard 04c20b84ad Merge pull request #1053 from mkborregaard/wand_edges
Make wand edges possible in statplots
2017-09-03 17:30:17 +02:00
Michael Krabbe Borregaard 04f5d7e411 Merge pull request #1064 from mkborregaard/fix-barwidth
Change default bar width to 0.8
2017-09-03 17:28:47 +02:00
Michael Krabbe Borregaard 82877dc53e Merge pull request #1009 from JackDevine/add-stride
Add stride to wireframe/surface
2017-09-03 07:35:35 +02:00
Jack Devine c7eb22021f Merge branch 'master' into add-stride 2017-09-03 13:04:32 +12:00
JackDevine 654fa0426b Remove documentation 2017-09-03 12:53:49 +12:00
Daniel Schwabeneder ae6c1c0c66 make it even more descriptive 2017-09-02 23:19:29 +02:00
Daniel Schwabeneder b3f5939689 make seriestype error more descriptive 2017-09-02 22:58:26 +02:00
Josef Heinen 184404beac Merge pull request #1065 from jheinen/master
gr: suppress default output in Juno
2017-09-02 08:03:01 -04:00
Daniel Schwabeneder 456b8258c3 add zerolines framestyle 2017-09-02 02:35:26 +02:00
Michael K. Borregaard a1896d189c Revert ordering 2017-09-01 16:31:13 +02:00
Michael K. Borregaard e47dde9f41 simplify
but creates type instability
2017-09-01 16:26:49 +02:00
Michael K. Borregaard 4be19ba6d8 Make wand edges possible in statplots 2017-09-01 15:53:26 +02:00
Michael Krabbe Borregaard 73a2839e34 Merge pull request #1037 from mkborregaard/hist-description
changes default histogram bins
2017-09-01 13:20:12 +02:00
Michael Krabbe Borregaard 224472c90a Merge pull request #1048 from mkborregaard/fix-margin-example
Reduce margin to 10 px
2017-09-01 10:40:37 +02:00
Michael K. Borregaard d77be82a99 fix classic typo 2017-09-01 10:36:44 +02:00
Josef Heinen 4320c7b9fb gr: suppress default output in Juno 2017-09-01 07:40:39 +02:00
Michael K. Borregaard 2dcf7fb3dd Change default bar width to 0.8 2017-08-31 23:58:07 +02:00
Michael K. Borregaard cd1913c008 Update bins description 2017-08-31 23:20:55 +02:00
Michael K. Borregaard 62694e4a93 Make Freedman-Diaconis the default 2017-08-31 23:19:00 +02:00
Michael K. Borregaard e92fbadc3a Update histogram normalization desc 2017-08-31 23:12:33 +02:00
Michael K. Borregaard 17c10bbe68 Reduce margin to 10 px 2017-08-31 23:01:46 +02:00
Pietro Vertechi 6c548f025e wip groupedbar 2017-08-31 19:34:38 +01:00
Michael Krabbe Borregaard cc15882faf Merge pull request #1058 from mkborregaard/histogram-like
Make it possible for downstream users (e.g. StatPlots) to define that a seriestype is "histogram-like", "line-like" or "surface-like"
2017-08-31 08:39:16 +02:00
Daniel Schwabeneder 3fd745a5df remove 0 tick label 2017-08-30 23:42:57 +02:00
Daniel Schwabeneder 5e968e0aa8 ticks to axes 2017-08-30 22:19:13 +02:00
Michael Krabbe Borregaard 1e3783b4dc Merge pull request #1052 from mkborregaard/fix-appveyor
add nightly and 32-bit to allow-failures in Appveyor
2017-08-30 14:56:46 +02:00
Michael K. Borregaard c355e02a20 add nightly and 32-bit to allow-failures 2017-08-30 14:56:02 +02:00
Josef Heinen e178dca167 Merge pull request #1060 from jheinen/master
gr: suppress default output in CI or Jupyter mode
2017-08-30 04:36:52 -04:00
Josef Heinen 8beee23e21 gr: suppress default output in CI or Jupyter mode
_update_min_padding() is called before the backend is "started".
In GR, this triggers an automatic initialization and starts the
default output driver (X11, Quartz or GDI). This doesn't make
sense in headless testing environments (CI) or when using Plots
in Jupyter notebooks.

These patches correct this behavour - but it's unclear (to me),
why the call of _update_min_padding() can't be postponed.
2017-08-30 09:59:23 +02:00
Michael K. Borregaard a894d377dc add vectors to hold histogram-like seriestypes and friends 2017-08-29 23:34:07 +02:00
Daniel Schwabeneder f41426c85a fix pyplot 2017-08-29 22:04:33 +02:00
Daniel Schwabeneder 41877e362a add origin framestyle 2017-08-29 20:36:59 +02:00
Daniel Schwabeneder de32b02c75 Merge pull request #1056 from jgoldfar/fix-incorrect-escape-v0.7
Fix incorrect escape sequence error on Julia nightly
2017-08-29 19:33:02 +02:00
Jonathan Goldfarb e3cba22ab7 Correct fix to warning for unknown grid argument. 2017-08-29 13:29:30 -04:00
Jonathan Goldfarb 25bcc3cbc1 Fix incorrect escape sequence error on v0.7. 2017-08-29 12:19:01 -04:00
piever ca5310025f Merge pull request #1033 from piever/group
Group now groups kw arguments as well
2017-08-29 17:16:40 +01:00
piever 5b9561c13e Merge pull request #1049 from piever/ticks
To be merged together with PlotUtils #26: accept axis with 4 ticks
2017-08-29 11:56:46 +01:00
Pietro Vertechi d594ac2f00 Accept axis with 4 ticks 2017-08-28 18:16:10 +01:00
Pietro Vertechi 5157089d87 group on a tuple of vectors 2017-08-27 18:56:10 +01:00
Michael Krabbe Borregaard d5b455b1f9 Merge pull request #1046 from mkborregaard/fix-tests-on-mac
Remove hidden files when checking version numbers
2017-08-27 11:12:59 +02:00
Michael K. Borregaard 6cb1ed6c92 Remove hidden files when checking version numbers 2017-08-27 11:10:06 +02:00
piever 3d0d52f82a Merge pull request #1043 from piever/grfixes
readd fill for cross and xcross on GR
2017-08-26 16:35:50 +01:00
Daniel Schwabeneder be04828d35 Merge pull request #1042 from daschw/ds-blackborder
make linecolor default to :auto
2017-08-26 15:58:11 +02:00
Josef Heinen 5f9aa2edc0 Merge pull request #1044 from jheinen/master
gr: defer the calculation of padding constraints
2017-08-26 13:05:30 +02:00
Josef Heinen a5751895f0 gr: update padding constraints before first plot 2017-08-26 06:49:00 -04:00
Josef Heinen 78b0918216 gr: defer the calculation of padding constraints 2017-08-25 13:54:56 -04:00
Pietro Vertechi 5a7ed24078 allow tuples 2017-08-25 17:01:29 +01:00
Pietro Vertechi 509f8f6a95 readd fill for cross and xcross on GR 2017-08-25 16:46:07 +01:00
Daniel Schwabeneder 6f3301e82f make linecolor default to auto 2017-08-25 14:16:53 +02:00
Josef Heinen 80f11ce30b Merge remote-tracking branch 'upstream/master' 2017-08-25 04:14:59 -04:00
Michael Krabbe Borregaard 95a6d24111 Merge pull request #990 from jverzani/patch-1
Update appveyor.yml
2017-08-25 08:51:30 +02:00
Michael Krabbe Borregaard 1fc2c511af Merge pull request #1030 from mkborregaard/pyplot-in-ijulia
Turn off gui for pyplot in ijulia
2017-08-25 08:47:24 +02:00
Josef Heinen 3bcaac7051 t push
Merge remote-tracking branch 'upstream/master'
2017-08-24 23:05:22 -04:00
Josef Heinen 25afd5c0e7 Merge pull request #1039 from jheinen/master
gr: always use NDCs when inquiring text extents
2017-08-25 05:05:13 +02:00
Josef Heinen dbbbeddad0 gr: always use NDCs when inquiring text extents 2017-08-24 22:32:05 -04:00
Josef Heinen c0f274d54b gr: always use NDCs when inquiring text extents 2017-08-24 22:27:04 -04:00
Michael Krabbe Borregaard 7816e078b5 Merge pull request #808 from darwindarak/dd/world-age
Hack around world age issue PyPlot (fix #734)
2017-08-24 22:53:04 +02:00
Daniel Schwabeneder 56bda82529 Merge pull request #1029 from daschw/ds-axes-border
Allow turning on/off the axes border (fix #1025)
2017-08-24 22:38:01 +02:00
Daniel Schwabeneder 54adc34348 fix glvisualize framestyle :none ticks 2017-08-24 22:21:13 +02:00
Darwin Darakananda a4ed700338 Use invokelatest to get around world age issue 2017-08-24 13:12:32 -07:00
Daniel Schwabeneder e2d107a70b add framestyle test example 2017-08-24 21:39:33 +02:00
Josef Heinen 31f080e4f4 Merge pull request #1038 from piever/grmargin
Adjust margin (ticks + margin given by user) with GR ( fix #1028 )
2017-08-24 20:58:41 +02:00
Daniel Schwabeneder 6e4b9af6b1 Merge pull request #780 from daschw/ds-ticks
WIP: Allow specifying the number of ticks by passing an Integer to the ticks attribute
2017-08-24 17:21:37 +02:00
Daniel Schwabeneder d301d2a06b fix ticks = nothing on pyplot, ... 2017-08-24 16:58:43 +02:00
Daniel Schwabeneder 2bbd4cbb17 clean up 2017-08-24 16:26:54 +02:00
Daniel Schwabeneder 5a2d39320f framestyle attribute for gr, pyplot and glvisualize 2017-08-24 16:13:01 +02:00
Pietro Vertechi 91158b1c20 add proper pad for ticks 2017-08-23 18:19:36 +01:00
Pietro Vertechi 06115f25ba factorize tickfont 2017-08-23 17:45:23 +01:00
Pietro Vertechi b3b533db94 fix margin in case there is no label (gr) 2017-08-23 14:10:35 +01:00
Pietro Vertechi e16125cb50 some GR margin fixes 2017-08-23 13:49:33 +01:00
Michael Krabbe Borregaard eb0dbac0c1 Merge pull request #1035 from piever/errorbar
don't draw fill for 1D markers in gr
2017-08-23 10:35:42 +02:00
Michael Krabbe Borregaard eb1d1876d3 Merge pull request #1034 from JuliaPlots/ChrisRackauckas-patch-1
Remove the -pre
2017-08-23 10:34:54 +02:00
Pietro Vertechi f751b1b7ff don't draw fill for 1D markers in gr 2017-08-23 08:40:19 +01:00
Christopher Rackauckas 34f9cfaa02 Remove the -pre
Plots.jl is no longer tested on the prereleases so it shouldn't say that they are supported.
2017-08-23 00:27:33 -07:00
Pietro Vertechi 6dba32bf99 only check kw is at least as long as group 2017-08-21 15:54:47 +01:00
Pietro Vertechi 9529246bfb keywords arguments of same length as series get grouped 2017-08-21 15:33:30 +01:00
Michael K. Borregaard 25774ee4c3 Turn off gui for pyplot in ijulia 2017-08-21 10:19:47 +02:00
Daniel Schwabeneder 1137513236 add aliases :box and :frame 2017-08-21 00:07:44 +02:00
Daniel Schwabeneder c76855698e Merge pull request #1027 from daschw/ds-datetime-ticks
Allow Date and DateTime as ticks (fix: #1026)
2017-08-20 22:51:26 +02:00
Daniel Schwabeneder be8c66adc9 fix polar plots on pyplot 2017-08-20 22:45:30 +02:00
Daniel Schwabeneder be4a374122 allow turning on/off the axes border 2017-08-20 21:55:21 +02:00
Daniel Schwabeneder d76a6d1c38 Allow and as ticks 2017-08-20 15:43:52 +02:00
Michael Krabbe Borregaard 5945196a4f Merge pull request #1023 from piever/pull-request/eea30fa2
RFC: added ribbon to plotly
2017-08-20 15:13:14 +02:00
Pietro Vertechi e164ea4b46 added default transparency to ribbon 2017-08-20 14:06:15 +01:00
Pietro Vertechi db3dca1d73 changed ribbon legend to line 2017-08-20 11:46:21 +01:00
Pietro Vertechi eea30fa253 added ribbon to plotly 2017-08-19 11:34:13 +01:00
Michael Krabbe Borregaard b585a0ef61 Merge pull request #1012 from mkborregaard/more_docstrings
Specified some docstrings
2017-08-18 10:30:02 +02:00
Michael K. Borregaard db82f22320 add the last docstrings 2017-08-18 09:48:36 +02:00
Michael K. Borregaard 66ce38d948 Specified some docstrings 2017-08-18 09:48:36 +02:00
Daniel Schwabeneder e61d435b00 Merge pull request #1020 from daschw/ds-precompile
reactivate precompilation
2017-08-18 00:58:55 +02:00
Daniel Schwabeneder d0a8985800 Merge pull request #1019 from daschw/ds-release
prepare release
2017-08-18 00:55:29 +02:00
Daniel Schwabeneder 4c1c092234 reactivate precompilation 2017-08-18 00:46:02 +02:00
Daniel Schwabeneder f02079dafe Merge pull request #1014 from daschw/ds-tests
import plot! placeholder from RecipesBase
2017-08-18 00:37:14 +02:00
Daniel Schwabeneder 4be0093a8a prepare release 2017-08-18 00:34:15 +02:00
Daniel Schwabeneder 130eb778d3 Merge pull request #1006 from daschw/ds-grid-axis
grid should be axis attribute (fix #675)
2017-08-17 23:57:59 +02:00
Daniel Schwabeneder be177e0f80 Merge pull request #1015 from daschw/ds-marker-z
only flip colorbar for marker_z on gr
2017-08-17 23:45:35 +02:00
Daniel Schwabeneder 42f54b8df9 remove Bools from _allGridArgs 2017-08-17 14:10:04 +02:00
Daniel Schwabeneder 4b60b05f75 update grid defaults and modify grid example 2017-08-17 13:42:54 +02:00
Michael Krabbe Borregaard 6afd0f9f82 Merge pull request #1011 from martinbiel/enforce-plotorder
Enforce plot order in user recipes
2017-08-17 09:10:01 +02:00
Daniel Schwabeneder 8288e85c25 only flip colorbar for marker_z 2017-08-16 22:32:00 +02:00
Daniel Schwabeneder bb2f4ff16b import inplace plot placeholder from RecipesBase 2017-08-16 21:05:05 +02:00
Daniel Schwabeneder 682ba1f764 allow non-boolean args for xgrid function 2017-08-16 19:41:13 +02:00
Daniel Schwabeneder e0c679f5ee magic grid argument 2017-08-16 17:45:32 +02:00
Martin Biel a1d0d028b6 Updated error text in _process_userrecipes, now uses correct variable 2017-08-16 10:16:37 +02:00
JackDevine 7741872578 Comma in the wrong place 2017-08-16 11:20:04 +12:00
JackDevine d1dcd536f5 I forgot a comma 2017-08-16 10:41:19 +12:00
JackDevine 177d380092 Added suggestions
Changed the interface to stride, which is a tuple. Also added aliases and a docstring in arg_desc.
2017-08-16 10:18:26 +12:00
Martin Biel 33a15f1e93 Process user recipes depth-first rather than breadth-first to enforce the plot order given in the recipe 2017-08-15 18:03:57 +02:00
JackDevine ad2eaf7aef Add stride to wireframe/surface
I only have this for PyPlot at the moment, I would be more than happy
to add other backends if people find it useful. Also, if people have
any ideas for aliases, then I would be happy to do that too.
2017-08-15 20:10:02 +12:00
Daniel Schwabeneder 23ae99b97e undo support for foreground_color_grid and foreground_color_axis attributes in plotly(js) 2017-08-11 12:57:11 +02:00
Daniel Schwabeneder 3c37de152d fix testimage 16 error - only add grid segments when ticks are defined 2017-08-10 22:54:45 +02:00
Daniel Schwabeneder 2dd99d053a make it work on all backends 2017-08-10 20:49:03 +02:00
Daniel Schwabeneder c60d66d94a make it work for gr, pyplot and plotly(js) 2017-08-10 17:46:11 +02:00
Daniel Schwabeneder 6b814b8dca initial commit mostly a copy of #695 2017-08-10 16:32:24 +02:00
Josef Heinen 11c71d7a5d Merge pull request #1005 from jheinen/master
gr: use correct gradient labels for scatter plot
2017-08-10 09:47:57 +02:00
Josef Heinen d90b2e6142 gr: use correct gradient labels for scatter plot 2017-08-10 09:31:54 +02:00
Josef Heinen 2ab7f3c767 Merge pull request #1003 from jheinen/master
gr: no longer handle '_' and '^' in text
2017-08-09 11:03:55 +02:00
Josef Heinen a937fa0ef8 gr: no longer handle '_' and '^' in text 2017-08-09 10:46:23 +02:00
Michael Krabbe Borregaard bc36749f6d Merge pull request #1002 from mkborregaard/mkb-precompile
allow precompilation
2017-08-09 08:12:45 +02:00
Michael K. Borregaard 88d1735380 allow precompilation 2017-08-09 08:12:22 +02:00
john verzani 9f0117d914 Update README.md
add appveyor badge. (But how does appveyor get run, as it doesn't seem to be current)
2017-08-01 15:48:12 -04:00
john verzani 8c3c07acb7 Update appveyor.yml
remove v0.5 testing from appveyor
2017-07-27 16:56:17 -04:00
john verzani 26a56c3105 Update appveyor.yml
add testing on v0.6 with 32 and 64 bit.
2017-07-27 15:48:52 -04:00
Daniel Schwabeneder dd526e00ab undo: fix passing ticks tuple on 0.6 2017-05-21 23:47:26 +02:00
Daniel Schwabeneder bad2ef63c6 fix passing ticks tuple on 0.6 2017-05-21 23:44:12 +02:00
Daniel Schwabeneder 93d16a27c1 undo unnecessary changes 2017-04-30 19:27:01 +02:00
Daniel Schwabeneder a602309a02 wip let axis limits expand 2017-04-30 19:02:42 +02:00
Daniel Schwabeneder 11e9eb3aa3 allow Int as input type for the ticks attribute to set the desired number of ticks 2017-04-23 20:30:48 +02:00
30 changed files with 1209 additions and 426 deletions
+57 -4
View File
@@ -3,22 +3,75 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.12!
- All new development should target 0.13!
- Minor version 0.11 is the last one to support Julia 0.5!!
- Critical bugfixes only
- `backports` branch is for Julia 0.4
- `backports` branch is for Julia 0.5
---
## (current master)
## 0.12.2
## 0.13.1
- fix a bug when passing a vector of functions with no bounds (e.g. `plot([sin, cos])`)
- export `pct` and `px` from Plots.PlotMeasures
## 0.13.0
- support `plotattributes` rather than `d` in recipes
- no longer export `w`, `h` and names from Measures.jl; use `using Plots.PlotMeasures` to get these names back
- `bar_width` now depends on the minimum distance between bars, not the mean
- better automatic x axis limits for plotting Functions
- `tick_direction` attribute now allows ticks to be on the inside of the plot border
- removed a bug where `p1 = plot(randn(10)); plot(p1, p2)` made `display(p1)` impossible
- allow `plot([])` to generate an empty plot
- add `origin` framestyle
- ensure finite bin number on histograms with only one unique value
- better automatic histogram bins for 2d histograms
- more informative error message on passing unsupported seriestype in a recipe
- allow grouping in user recipes
- GR now has `line_z` and `fill_z` attributes for determining the color of shapes and lines
- change GR default view angle for 3D plots to match that of PyPlot
- fix `clims` on GR
- fix `marker_z` for plotly backend
- implement `framestyle` for plotly
- fix logscale bug error for values < 1e-16 on pyplot
- fix an issue on pyplot where >1 colorbar would be shown if there was >1 series
- fix `writemime` for eps
## 0.12.4
- added a new `framestyle` argument with choices: :box, :semi, :axes, :grid and :none
- changed the default bar width to 0.8
- added working ribbon to plotly backend
- ensure that automatic ticks always generate 4 to 8 ticks
- group now groups keyword arguments of the same length as the input
- allow passing DateTime objects as ticks
- allow specifying the number of ticks as an integre
- fix bug on errorbars in gr
- fixed some but not all world age issues
- better margin with room for text
- added a `match` option for linecolor
- better error message un unsupported series types
- add a 'stride' keyword for the pyplot backend
## 0.12.3
- new grid line style defaults
- `grid` is now an axis attribute and a magic argument: it is now possible to modify the grid line style, alpha and line width
- Enforce plot order in user recipes
- import `plot!` from RecipesBase
- GR no longer automatically handles _ and ^ in texts
- fix GR colorbar for scatter plots
#### 0.12.2
- fix an issue with Juno/PlotlyJS compatibility on new installations
- fix markers not showing up in seriesrecipes using :scatter
- don't use pywrap in the pyplot backend
- improve the bottom margin for the gr backend
## 0.12.1
#### 0.12.1
- fix deprecation warnings
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
+1
View File
@@ -1,6 +1,7 @@
# Plots
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/tbreloff/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/tbreloff/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
+2 -2
View File
@@ -1,6 +1,6 @@
julia 0.6-pre
julia 0.6
RecipesBase 0.2.0
RecipesBase 0.2.3
PlotUtils 0.4.1
PlotThemes 0.1.3
Reexport
+8 -2
View File
@@ -1,7 +1,13 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
matrix:
allow_failures:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" #check and address
- 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"
+48 -3
View File
@@ -8,7 +8,7 @@ import StaticArrays
using StaticArrays.FixedSizeArrays
@reexport using RecipesBase
import RecipesBase: plot, animate
import RecipesBase: plot, plot!, animate
using Base.Meta
@reexport using PlotUtils
@reexport using PlotThemes
@@ -52,6 +52,8 @@ export
yflip!,
xaxis!,
yaxis!,
xgrid!,
ygrid!,
xlims,
ylims,
@@ -131,11 +133,20 @@ ignorenan_extrema(x) = Base.extrema(x)
# ---------------------------------------------------------
import Measures
module PlotMeasures
import Measures
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
const BBox = Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h
end
using .PlotMeasures
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
# ---------------------------------------------------------
include("types.jl")
@@ -186,33 +197,65 @@ include("output.jl")
@shorthands quiver
@shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = 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!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
let PlotOrSubplot = Union{Plot, Subplot}
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
@@ -230,6 +273,8 @@ let PlotOrSubplot = Union{Plot, Subplot}
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
+7 -2
View File
@@ -1,4 +1,4 @@
"Represents an animation object"
immutable Animation
dir::String
frames::Vector{String}
@@ -9,6 +9,11 @@ function Animation()
Animation(tmpdir, String[])
end
"""
frame(animation[, plot])
Add a plot (the current plot if not specified) to an existing animation
"""
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
@@ -81,7 +86,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString;
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
You may also need to install the imagemagick c++ library through your operating system.
You may also need to install the imagemagick c++ library through your operating system.
Will try ffmpeg, but it's lower quality...)""")
# low quality
+9 -5
View File
@@ -21,7 +21,7 @@ const _arg_desc = KW(
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto. For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
@@ -40,7 +40,7 @@ const _arg_desc = KW(
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a PDF with integral of 1) and :density (only normalize in respect to bin sizes).",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
: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`.",
@@ -76,7 +76,6 @@ const _arg_desc = KW(
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
@@ -84,7 +83,6 @@ const _arg_desc = KW(
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.",
:grid => "Bool. Show the grid lines?",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
@@ -95,6 +93,7 @@ const _arg_desc = KW(
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
# axis args
:guide => "String. Axis guide (label).",
@@ -111,5 +110,10 @@ const _arg_desc = KW(
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`"
)
+125 -16
View File
@@ -80,9 +80,13 @@ const _typeAliases = Dict{Symbol,Symbol}(
add_non_underscore_aliases!(_typeAliases)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins)
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
const _histogram_like = [:histogram, :barhist, :barbins]
const _line_like = [:line, :path, :steppre, :steppost]
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
like_histogram(seriestype::Symbol) = seriestype in _histogram_like
like_line(seriestype::Symbol) = seriestype in _line_like
like_surface(seriestype::Symbol) = seriestype in _surface_like
is3d(seriestype::Symbol) = seriestype in _3dTypes
is3d(series::Series) = is3d(series.d)
@@ -163,6 +167,34 @@ const _scaleAliases = Dict{Symbol,Symbol}(
:log => :log10,
)
const _allGridSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on,
:none, :off,]
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
hasgrid(arg::Void, letter) = false
hasgrid(arg::Bool, letter) = arg
function hasgrid(arg::Symbol, letter)
if arg in _allGridSyms
arg in (:all, :both, :on) || contains(string(arg), string(letter))
else
warn("Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead.")
true
end
end
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
const _framestyleAliases = Dict{Symbol, Symbol}(
:frame => :box,
:border => :box,
:on => :box,
:transparent => :semi,
:semitransparent => :semi,
)
const _bar_width = 0.8
# -----------------------------------------------------------------------------
const _series_defaults = KW(
@@ -172,7 +204,7 @@ const _series_defaults = KW(
:seriestype => :path,
:linestyle => :solid,
:linewidth => :auto,
:linecolor => :match,
:linecolor => :auto,
:linealpha => nothing,
:fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match,
@@ -214,6 +246,7 @@ const _series_defaults = KW(
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
# one logical series to be broken up (path and markers, for example)
:hover => nothing, # text to display when hovering over the data points
:stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride.
)
@@ -247,7 +280,6 @@ const _subplot_defaults = KW(
:background_color_inside => :match, # background inside grid
:foreground_color_subplot => :match, # default for other fg colors... match takes plot default
:foreground_color_legend => :match, # foreground of legend
:foreground_color_grid => :match, # grid color
:foreground_color_title => :match, # title color
:color_palette => :auto,
:legend => :best,
@@ -255,7 +287,6 @@ const _subplot_defaults = KW(
:colorbar => :legend,
:clims => :auto,
:legendfont => font(8),
:grid => true,
:annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal
@@ -266,6 +297,7 @@ const _subplot_defaults = KW(
:bottom_margin => :match,
:subplot_index => -1,
:colorbar_title => "",
:framestyle => :axes,
)
const _axis_defaults = KW(
@@ -285,6 +317,12 @@ const _axis_defaults = KW(
:discrete_values => [],
:formatter => :auto,
:mirror => false,
:grid => true,
:foreground_color_grid => :match, # grid color
:gridalpha => 0.1,
:gridstyle => :solid,
:gridlinewidth => 0.5,
:tick_direction => :in,
)
const _suppress_warnings = Set{Symbol}([
@@ -402,7 +440,7 @@ add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_co
add_aliases(:foreground_color_axis, :fg_axis, :fgaxis, :fgcolor_axis, :fg_color_axis, :foreground_axis,
:foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor)
add_aliases(:foreground_color_border, :fg_border, :fgborder, :fgcolor_border, :fg_color_border, :foreground_border,
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor, :border)
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor)
add_aliases(:foreground_color_text, :fg_text, :fgtext, :fgcolor_text, :fg_color_text, :foreground_text,
:foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor)
add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_color_guide, :foreground_guide,
@@ -414,6 +452,7 @@ add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
# series attributes
add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt)
@@ -469,7 +508,11 @@ add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesa
add_aliases(:html_output_format, :format, :fmt, :html_format)
add_aliases(:orientation, :direction, :dir)
add_aliases(:inset_subplots, :inset, :floating)
add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str)
add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw)
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
add_aliases(: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 all pluralized forms to the _keyAliases dict
for arg in keys(_series_defaults)
@@ -488,7 +531,6 @@ end
`default(; kw...)` will set the current default value for each key/value pair
`default(d, key)` returns the key from d if it exists, otherwise `default(key)`
"""
function default(k::Symbol)
k = get(_keyAliases, k, k)
for defaults in _all_defaults
@@ -645,6 +687,36 @@ function processFillArg(d::KW, arg)
return
end
function processGridArg!(d::KW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
d[Symbol(letter, :grid)] = hasgrid(arg, letter)
elseif allStyles(arg)
d[Symbol(letter, :gridstyle)] = arg
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[Symbol(letter, :gridlinewidth)] = arg.width)
arg.color == nothing || (d[Symbol(letter, :foreground_color_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color))
arg.alpha == nothing || (d[Symbol(letter, :gridalpha)] = arg.alpha)
arg.style == nothing || (d[Symbol(letter, :gridstyle)] = arg.style)
# linealpha
elseif allAlphas(arg)
d[Symbol(letter, :gridalpha)] = arg
# linewidth
elseif allReals(arg)
d[Symbol(letter, :gridlinewidth)] = arg
# color
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
warn("Skipped grid arg $arg.")
end
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
_replace_markershape(shape) = shape
@@ -666,6 +738,7 @@ function preprocessArgs!(d::KW)
if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
d[:ticks] = nothing
d[:foreground_color_border] = RGBA(0,0,0,0)
d[:foreground_color_axis] = RGBA(0,0,0,0)
d[:grid] = false
delete!(d, :axis)
end
@@ -688,6 +761,22 @@ function preprocessArgs!(d::KW)
end
end
# handle grid args common to all axes
args = pop!(d, :grid, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processGridArg!(d, arg, letter)
end
end
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :grid)
args = pop!(d, gridsym, ())
for arg in wraptuple(args)
processGridArg!(d, arg, letter)
end
end
# handle line args
for arg in wraptuple(pop!(d, :line, ()))
processLineArg(d, arg)
@@ -752,6 +841,11 @@ function preprocessArgs!(d::KW)
d[:colorbar] = convertLegendValue(d[:colorbar])
end
# framestyle
if haskey(d, :framestyle) && haskey(_framestyleAliases, d[:framestyle])
d[:framestyle] = _framestyleAliases[d[:framestyle]]
end
# warnings for moved recipes
st = get(d, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
@@ -771,21 +865,29 @@ end
# this is when given a vector-type of values to group by
function extractGroupArgs(v::AVec, args...)
function extractGroupArgs(v::AVec, args...; legendEntry = string)
groupLabels = sort(collect(unique(v)))
n = length(groupLabels)
if n > 100
warn("You created n=$n groups... Is that intended?")
end
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
GroupBy(map(string, groupLabels), groupIds)
GroupBy(map(legendEntry, groupLabels), groupIds)
end
legendEntryFromTuple(ns::Tuple) = string(("$n " for n in 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...))
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
# expecting a mapping of "group label" to "group indices"
function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...)
groupLabels = sortedkeys(idxmap)
groupIds = VecI[collect(idxmap[k]) for k in groupLabels]
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
GroupBy(groupLabels, groupIds)
end
@@ -943,7 +1045,6 @@ const _match_map = KW(
:background_color_legend => :background_color_subplot,
:background_color_inside => :background_color_subplot,
:foreground_color_legend => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_title => :foreground_color_subplot,
:left_margin => :margin,
:top_margin => :margin,
@@ -957,6 +1058,7 @@ const _match_map2 = KW(
:foreground_color_subplot => :foreground_color,
:foreground_color_axis => :foreground_color_subplot,
:foreground_color_border => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_guide => :foreground_color_subplot,
:foreground_color_text => :foreground_color_subplot,
)
@@ -1091,7 +1193,6 @@ function _update_subplot_colors(sp::Subplot)
# foreground colors
color_or_nothing!(sp.attr, :foreground_color_subplot)
color_or_nothing!(sp.attr, :foreground_color_legend)
color_or_nothing!(sp.attr, :foreground_color_grid)
color_or_nothing!(sp.attr, :foreground_color_title)
return
end
@@ -1143,6 +1244,7 @@ function _update_axis_colors(axis::Axis)
color_or_nothing!(axis.d, :foreground_color_border)
color_or_nothing!(axis.d, :foreground_color_guide)
color_or_nothing!(axis.d, :foreground_color_text)
color_or_nothing!(axis.d, :foreground_color_grid)
return
end
@@ -1179,6 +1281,8 @@ end
# -----------------------------------------------------------------------------
has_black_border_for_default(st) = error("The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.")
has_black_border_for_default(st::Function) = error("The seriestype attribute only accepts Symbols, you passed the function $st.")
function has_black_border_for_default(st::Symbol)
like_histogram(st) || st in (:hexbin, :bar, :shape)
end
@@ -1248,12 +1352,14 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
# update other colors
for s in (:line, :marker, :fill)
csym, asym = Symbol(s,:color), Symbol(s,:alpha)
d[csym] = if d[csym] == :match
d[csym] = if d[csym] == :auto
plot_color(if has_black_border_for_default(d[:seriestype]) && s == :line
sp[:foreground_color_subplot]
else
d[:seriescolor]
end, d[asym])
elseif d[csym] == :match
plot_color(d[:seriescolor], d[asym])
else
getSeriesRGBColor(d[csym], d[asym], sp, plotIndex)
end
@@ -1266,13 +1372,16 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
getSeriesRGBColor(d[:markerstrokecolor], d[:markerstrokealpha], sp, plotIndex)
end
# if marker_z or line_z are set, ensure we have a gradient
# if marker_z, fill_z or line_z are set, ensure we have a gradient
if d[:marker_z] != nothing
ensure_gradient!(d, :markercolor, :markeralpha)
end
if d[:line_z] != nothing
ensure_gradient!(d, :linecolor, :linealpha)
end
if d[:fill_z] != nothing
ensure_gradient!(d, :fillcolor, :fillalpha)
end
# scatter plots don't have a line, but must have a shape
if d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d)
+92 -36
View File
@@ -181,15 +181,27 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
end
# get a list of well-laid-out ticks
scaled_ticks = if ticks == nothing
optimize_ticks(
if ticks == nothing
scaled_ticks = optimize_ticks(
sf(amin),
sf(amax);
k_min = 5, # minimum number of ticks
k_min = 4, # minimum number of ticks
k_max = 8, # maximum number of ticks
)[1]
elseif typeof(ticks) <: Int
scaled_ticks, viewmin, viewmax = optimize_ticks(
sf(amin),
sf(amax);
k_min = ticks, # minimum number of ticks
k_max = ticks, # maximum number of ticks
k_ideal = ticks,
# `strict_span = false` rewards cases where the span of the
# chosen ticks is not too much bigger than amin - amax:
strict_span = false,
)
axis[:lims] = map(invscalefunc(scale), (viewmin, viewmax))
else
map(sf, filter(t -> amin <= t <= amax, ticks))
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end
unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
@@ -216,7 +228,7 @@ end
# return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(axis::Axis)
ticks = axis[:ticks]
ticks = _transform_ticks(axis[:ticks])
ticks in (nothing, false) && return nothing
dvals = axis[:discrete_values]
@@ -226,7 +238,7 @@ function get_ticks(axis::Axis)
elseif ticks == :auto
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
elseif typeof(ticks) <: AVec
elseif typeof(ticks) <: Union{AVec, Int}
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
elseif typeof(ticks) <: NTuple{2, Any}
@@ -246,6 +258,10 @@ function get_ticks(axis::Axis)
end
end
_transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
# -------------------------------------------------------------------------
@@ -349,7 +365,7 @@ function expand_extrema!(sp::Subplot, d::KW)
bw = d[:bar_width]
if bw == nothing
bw = d[:bar_width] = ignorenan_mean(diff(data))
bw = d[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
end
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
@@ -490,38 +506,78 @@ function axis_drawing_info(sp::Subplot)
ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
spine_segs = Segments(2)
grid_segs = Segments(2)
xaxis_segs = Segments(2)
yaxis_segs = Segments(2)
xtick_segs = Segments(2)
ytick_segs = Segments(2)
xgrid_segs = Segments(2)
ygrid_segs = Segments(2)
xborder_segs = Segments(2)
yborder_segs = Segments(2)
if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
t1 = invf(f(ymin) + 0.015*(f(ymax)-f(ymin)))
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin)))
if !(sp[:framestyle] == :none)
# xaxis
sp[:framestyle] in (:grid, :origin, :zerolines) || push!(xaxis_segs, (xmin,ymin), (xmax,ymin)) # bottom spine / xaxis
if sp[:framestyle] in (:origin, :zerolines)
push!(xaxis_segs, (xmin, 0.0), (xmax, 0.0))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && 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,ymax), (xmax,ymax)) # top spine
if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(ymin) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t2 = invf(f(ymax) - 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
# push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
for xtick in xticks[1]
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid
# push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
for xtick in xticks[1]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xaxis[:mirror] ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, t1), (xtick, t2)) # vertical grid
end
end
# yaxis
sp[:framestyle] in (:grid, :origin, :zerolines) || push!(yaxis_segs, (xmin,ymin), (xmin,ymax)) # left spine / yaxis
if sp[:framestyle] in (:origin, :zerolines)
push!(yaxis_segs, (0.0, ymin), (0.0, ymax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (xmax,ymin), (xmax,ymax)) # right spine
if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(xmin) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t2 = invf(f(xmax) - 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
for ytick in yticks[1]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
yaxis[:mirror] ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
end
end
end
if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
t1 = invf(f(xmin) + 0.015*(f(xmax)-f(xmin)))
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
# push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
for ytick in yticks[1]
push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick
push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
# push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
end
end
xticks, yticks, spine_segs, grid_segs
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs
end
+3
View File
@@ -6,7 +6,10 @@ const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[]
const _initialized_backends = Set{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")
+60 -13
View File
@@ -24,7 +24,8 @@ const _glvisualize_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :colorbar,
:marker_z,
:line_z,
:levels,
@@ -38,7 +39,9 @@ const _glvisualize_attr = merge_with_base_supported([
:clims,
:inset_subplots,
:dpi,
:hover
:hover,
:framestyle,
:tick_direction,
])
const _glvisualize_seriestype = [
:path, :shape,
@@ -602,7 +605,7 @@ end
pointsize(font) = font.pointsize * 2
function draw_ticks(
axis, ticks, isx, lims, m, text = "",
axis, ticks, isx, isorigin, lims, m, text = "",
positions = Point2f0[], offsets=Vec2f0[]
)
sz = pointsize(axis[:tickfont])
@@ -620,7 +623,11 @@ function draw_ticks(
for (cv, dv) in zip(ticks...)
x, y = cv, lims[1]
xy = isx ? (x, y) : (y, x)
xy = if isorigin
isx ? (x, 0) : (0, x)
else
isx ? (x, y) : (y, x)
end
_pos = m * GeometryTypes.Vec4f0(xy[1], xy[2], 0, 1)
startpos = Point2f0(_pos[1], _pos[2]) - axis_gap
str = string(dv)
@@ -676,31 +683,62 @@ function text_model(font, pivot)
end
end
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
xticks, yticks, spine_segs, grid_segs = Plots.axis_drawing_info(sp)
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
c = Colors.color(Plots.gl_color(sp[:foreground_color_grid]))
xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
ygc = Colors.color(Plots.gl_color(yaxis[:foreground_color_grid]))
axis_vis = []
if sp[:grid]
grid = draw_grid_lines(sp, grid_segs, 1f0, :dot, model, RGBA(c, 0.3f0))
if xaxis[:grid]
grid = draw_grid_lines(sp, xgrid_segs, xaxis[:gridlinewidth], xaxis[:gridstyle], model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, grid)
end
if alpha(xaxis[:foreground_color_border]) > 0
spine = draw_grid_lines(sp, spine_segs, 1f0, :solid, model, RGBA(c, 1.0f0))
if yaxis[:grid]
grid = draw_grid_lines(sp, ygrid_segs, yaxis[:gridlinewidth], yaxis[:gridstyle], model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, grid)
end
xac = Colors.color(Plots.gl_color(xaxis[:foreground_color_axis]))
yac = Colors.color(Plots.gl_color(yaxis[:foreground_color_axis]))
if alpha(xaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, xspine_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, yspine_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine)
end
if sp[:framestyle] in (:zerolines, :grid)
if alpha(xaxis[:foreground_color_grid]) > 0
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_grid]) > 0
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, spine)
end
else
if alpha(xaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine)
end
end
fcolor = Plots.gl_color(xaxis[:foreground_color_axis])
xlim = Plots.axis_limits(xaxis)
ylim = Plots.axis_limits(yaxis)
if !(xaxis[:ticks] in (nothing, false, :none))
if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none)
ticklabels = map(model) do m
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(xaxis, xticks, true, ylim, m)
t, positions, offsets = draw_ticks(xaxis, xticks, true, sp[:framestyle] == :origin, ylim, m)
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(
yaxis, yticks, false, xlim, m,
yaxis, yticks, false, sp[:framestyle] == :origin, xlim, m,
t, positions, offsets
)
end
@@ -714,6 +752,15 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end
xbc = Colors.color(Plots.gl_color(xaxis[:foreground_color_border]))
ybc = Colors.color(Plots.gl_color(yaxis[:foreground_color_border]))
intensity = sp[:framestyle] == :semi ? 0.5f0 : 1.0f0
if sp[:framestyle] in (:box, :semi)
xborder = draw_grid_lines(sp, xborder_segs, intensity, :solid, model, RGBA(xbc, intensity))
yborder = draw_grid_lines(sp, yborder_segs, intensity, :solid, model, RGBA(ybc, intensity))
push!(axis_vis, xborder, yborder)
end
area_w = GeometryTypes.widths(area)
if sp[:title] != ""
tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title])
+223 -116
View File
@@ -20,8 +20,9 @@ const _gr_attr = merge_with_base_supported([
:title, :window_title,
:guide, :lims, :ticks, :scale, :flip,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar,
:marker_z, :levels,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:fill_z, :line_z, :marker_z, :levels,
:ribbon, :quiver,
:orientation,
:overwrite_figure,
@@ -31,6 +32,8 @@ const _gr_attr = merge_with_base_supported([
:inset_subplots,
:bar_width,
:arrow,
:framestyle,
:tick_direction,
])
const _gr_seriestype = [
:path, :scatter,
@@ -179,7 +182,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 || search(s, '_') != 0 || search(s, '^') != 0
elseif search(s, '\\') != 0
GR.inqtextext(x, y, s)
else
GR.inqtext(x, y, s)
@@ -191,7 +194,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 || search(s, '_') != 0 || search(s, '^') != 0
elseif search(s, '\\') != 0
GR.textext(x, y, s)
else
GR.text(x, y, s)
@@ -262,17 +265,18 @@ function gr_fill_viewport(vp::AVec{Float64}, c)
end
normalize_zvals(zv::Void) = zv
function normalize_zvals(zv::AVec)
normalize_zvals(args...) = nothing
function normalize_zvals(zv::AVec, clims::NTuple{2, <:Real})
vmin, vmax = ignorenan_extrema(zv)
isfinite(clims[1]) && (vmin = clims[1])
isfinite(clims[2]) && (vmax = clims[2])
if vmin == vmax
zeros(length(zv))
else
(zv - vmin) ./ (vmax - vmin)
clamp.((zv - vmin) ./ (vmax - vmin), 0, 1)
end
end
gr_alpha(α::Void) = 1
gr_alpha(α::Real) = α
@@ -325,18 +329,22 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
cfuncind(ci)
GR.settransparency(_gr_gradient_alpha[ci-999])
end
gr_draw_marker(x[i], y[i], msi, shape)
# don't draw filled area if marker shape is 1D
if !(shape in (:hline, :vline, :+, :x))
gr_draw_marker(x[i], y[i], msi, shape)
end
end
end
end
function gr_draw_markers(series::Series, x, y)
function gr_draw_markers(series::Series, x, y, clims)
isempty(x) && return
mz = normalize_zvals(series[:marker_z])
mz = normalize_zvals(series[:marker_z], clims)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_draw_markers(series, x, y, series[:markersize], mz)
if mz != nothing
gr_colorbar(series[:subplot])
if hascolorbar(series[:subplot])
GR.setscale(0)
gr_colorbar(series[:subplot], clims)
end
end
@@ -440,11 +448,21 @@ end
# add the colorbar
function gr_colorbar(sp::Subplot)
if sp[:colorbar] != :none
gr_set_viewport_cmap(sp)
GR.colorbar()
gr_set_viewport_plotarea()
end
gr_set_viewport_cmap(sp)
GR.colorbar()
gr_set_viewport_plotarea()
end
function gr_colorbar(sp::Subplot, clims)
xmin, xmax = gr_xy_axislims(sp)[1:2]
gr_set_viewport_cmap(sp)
l = zeros(Int32, 1, 256)
l[1,:] = Int[round(Int, _i) for _i in linspace(1000, 1255, 256)]
GR.setwindow(xmin, xmax, clims[1], clims[2])
GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l)
ztick = 0.5 * GR.tick(clims[1], clims[2])
GR.axes(0, ztick, xmax, clims[1], 0, 1, 0.005)
gr_set_viewport_plotarea()
end
gr_view_xcenter() = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2])
@@ -537,40 +555,91 @@ function gr_display(plt::Plot)
end
function gr_set_xticks_font(sp)
flip = sp[:yaxis][:flip]
mirror = sp[:xaxis][:mirror]
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = (mirror ? :bottom : :top),
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation])
return flip, mirror
end
function gr_set_yticks_font(sp)
flip = sp[:xaxis][:flip]
mirror = sp[:yaxis][:mirror]
gr_set_font(sp[:yaxis][:tickfont],
halign = (mirror ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
color = sp[:yaxis][:foreground_color_axis],
rotation = sp[:yaxis][:rotation])
return flip, mirror
end
function gr_get_ticks_size(ticks, i)
GR.savestate()
GR.selntran(0)
l = 0.0
for (cv, dv) in zip(ticks...)
tb = gr_inqtext(0, 0, string(dv))[i]
tb_min, tb_max = extrema(tb)
l = max(l, tb_max - tb_min)
end
GR.restorestate()
return l
end
function _update_min_padding!(sp::Subplot{GRBackend})
leftpad = 10mm
toppad = 2mm
rightpad = 2mm
bottompad = 6mm
if !haskey(ENV, "GKSwstype")
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
ENV["GKSwstype"] = "svg"
end
end
# Add margin given by the user
leftpad = 2mm + sp[:left_margin]
toppad = 2mm + sp[:top_margin]
rightpad = 4mm + sp[:right_margin]
bottompad = 2mm + sp[:bottom_margin]
# Add margin for title
if sp[:title] != ""
toppad += 5mm
end
if sp[:xaxis][:guide] != ""
xticks = axis_drawing_info(sp)[1]
if !(xticks in (nothing, false))
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = :top,
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation])
h = 0
for (cv, dv) in zip(xticks...)
tbx, tby = gr_inqtext(0, 0, string(dv))
h = max(h, tby[2] - tby[1])
end
bottompad += 1mm + gr_plot_size[2] * h * px
# Add margin for x and y ticks
xticks, yticks = axis_drawing_info(sp)[1:2]
if !(xticks in (nothing, false))
flip, mirror = gr_set_xticks_font(sp)
l = gr_get_ticks_size(xticks, 2)
if mirror
toppad += 1mm + gr_plot_size[2] * l * px
else
bottompad += 4mm
bottompad += 1mm + gr_plot_size[2] * l * px
end
end
if !(yticks in (nothing, false))
flip, mirror = gr_set_yticks_font(sp)
l = gr_get_ticks_size(yticks, 1)
if mirror
rightpad += 1mm + gr_plot_size[1] * l * px
else
leftpad += 1mm + gr_plot_size[1] * l * px
end
end
# Add margin for x label
if sp[:xaxis][:guide] != ""
bottompad += 4mm
end
# Add margin for y label
if sp[:yaxis][:guide] != ""
leftpad += 4mm
end
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
_update_min_padding!(sp)
# the viewports for this subplot
viewport_subplot = gr_viewport_from_bbox(sp, bbox(sp), w, h, viewport_canvas)
viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas)
@@ -605,14 +674,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# reduced from before... set some flags based on the series in this subplot
# TODO: can these be generic flags?
outside_ticks = false
cmap = false
draw_axes = true
cmap = hascolorbar(sp)
draw_axes = sp[:framestyle] != :none
# axes_2d = true
for series in series_list(sp)
st = series[:seriestype]
if st in (:contour, :surface, :heatmap) || series[:marker_z] != nothing
cmap = true
end
if st == :pie
draw_axes = false
end
@@ -626,7 +692,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
end
if cmap && sp[:colorbar] != :none
if cmap
# note: add extra midpadding on the right for the colorbar
viewport_plotarea[2] -= 0.1
end
@@ -684,17 +750,16 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
GR.setspace(zmin, zmax, 40, 70)
GR.setspace(zmin, zmax, 35, 60)
xtick = GR.tick(xmin, xmax) / 2
ytick = GR.tick(ymin, ymax) / 2
ztick = GR.tick(zmin, zmax) / 2
ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1])
# GR.setlinetype(GR.LINETYPE_DOTTED)
if sp[:grid]
GR.grid3d(xtick, 0, ztick, xmin, ymax, zmin, 2, 0, 2)
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
end
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)
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
@@ -709,58 +774,85 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setwindow(xmin, xmax, ymin, ymax)
end
xticks, yticks, spine_segs, grid_segs = axis_drawing_info(sp)
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
# @show xticks yticks #spine_segs grid_segs
# draw the grid lines
if sp[:grid]
if xaxis[:grid]
# gr_set_linecolor(sp[:foreground_color_grid])
# GR.grid(xtick, ytick, 0, 0, majorx, majory)
gr_set_line(1, :dot, sp[:foreground_color_grid])
GR.settransparency(0.5)
gr_polyline(coords(grid_segs)...)
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
GR.settransparency(xaxis[:gridalpha])
gr_polyline(coords(xgrid_segs)...)
end
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
GR.settransparency(yaxis[:gridalpha])
gr_polyline(coords(ygrid_segs)...)
end
GR.settransparency(1.0)
# spine (border) and tick marks
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
# axis lines
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(spine_segs)...)
gr_polyline(coords(xspine_segs)...)
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(yspine_segs)...)
GR.setclip(1)
if !(xticks in (nothing, false))
# axis ticks
if sp[:framestyle] in (:zerolines, :grid)
gr_set_line(1, :solid, xaxis[:foreground_color_grid])
GR.settransparency(xaxis[:gridalpha])
else
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
end
GR.setclip(0)
gr_polyline(coords(xtick_segs)...)
if sp[:framestyle] in (:zerolines, :grid)
gr_set_line(1, :solid, yaxis[:foreground_color_grid])
GR.settransparency(yaxis[:gridalpha])
else
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
end
GR.setclip(0)
gr_polyline(coords(ytick_segs)...)
GR.setclip(1)
# tick marks
if !(xticks in (:none, nothing, false))
# x labels
flip = sp[:yaxis][:flip]
mirror = sp[:xaxis][:mirror]
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = (mirror ? :bottom : :top),
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation])
flip, mirror = gr_set_xticks_font(sp)
for (cv, dv) in zip(xticks...)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(cv, xor(flip, mirror) ? ymax : ymin)
xi, yi = GR.wctondc(cv, sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? ymax : ymin)
# @show cv dv ymin xi yi flip mirror (flip $ mirror)
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3, string(dv))
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0), string(dv))
end
end
if !(yticks in (nothing, false))
if !(yticks in (:none, nothing, false))
# y labels
flip = sp[:xaxis][:flip]
mirror = sp[:yaxis][:mirror]
gr_set_font(sp[:yaxis][:tickfont],
halign = (mirror ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
color = sp[:yaxis][:foreground_color_axis],
rotation = sp[:yaxis][:rotation])
flip, mirror = gr_set_yticks_font(sp)
for (cv, dv) in zip(yticks...)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(xor(flip, mirror) ? xmax : xmin, cv)
xi, yi = GR.wctondc(sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? xmax : xmin, cv)
# @show cv dv xmin xi yi
gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv))
gr_text(xi + (mirror ? 1 : -1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), yi, string(dv))
end
end
# border
intensity = sp[:framestyle] == :semi ? 0.5 : 1.0
if sp[:framestyle] in (:box, :semi)
gr_set_line(intensity, :solid, xaxis[:foreground_color_border])
GR.settransparency(intensity)
gr_polyline(coords(xborder_segs)...)
gr_set_line(intensity, :solid, yaxis[:foreground_color_border])
GR.settransparency(intensity)
gr_polyline(coords(yborder_segs)...)
end
end
# end
@@ -794,6 +886,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# this needs to be here to point the colormap to the right indices
GR.setcolormap(1000 + GR.COLORMAP_COOLWARM)
# calculate the colorbar limits once for a subplot
clims = get_clims(sp)
for (idx, series) in enumerate(series_list(sp))
st = series[:seriestype]
@@ -802,6 +897,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_set_gradient(series[:fillcolor]) #, series[:fillalpha])
elseif series[:marker_z] != nothing
series[:markercolor] = gr_set_gradient(series[:markercolor])
elseif series[:line_z] != nothing
series[:linecolor] = gr_set_gradient(series[:linecolor])
elseif series[:fill_z] != nothing
series[:fillcolor] = gr_set_gradient(series[:fillcolor])
end
GR.savestate()
@@ -840,36 +939,42 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if frng != nothing
GR.setfillintstyle(GR.INTSTYLE_SOLID)
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
for (i,rng) in enumerate(iter_segments(series[:x], series[:y]))
if length(rng) > 1
gr_set_fillcolor(_cycle(series[:fillcolor], i))
fx = _cycle(x, vcat(rng, reverse(rng)))
fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
# @show i rng fx fy
GR.fillarea(fx, fy)
end
for i in 1:length(x) - 1
gr_set_fillcolor(get_fillcolor(sp, series, i))
xseg = _cycle(x, [i, i+1, i+1, i])
yseg = [_cycle(fr_from, [i, i+1]); _cycle(fr_to, [i+1, i])]
series[:fillalpha] != nothing && GR.settransparency(series[:fillalpha])
GR.fillarea(xseg, yseg)
end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.settransparency(1)
cmap && gr_colorbar(sp, clims)
end
# draw the line(s)
if st == :path
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
gr_polyline(x, y; arrowside = arrowside)
for i in 1:length(x) - 1
xseg = x[i:(i + 1)]
yseg = y[i:(i + 1)]
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
arrowside = (i == length(y) - 1) && isa(series[:arrow], Arrow) ? series[:arrow].side : :none
gr_polyline(xseg, yseg; arrowside = arrowside)
end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
cmap && gr_colorbar(sp, clims)
end
end
if series[:markershape] != :none
gr_draw_markers(series, x, y)
if series[:marker_z] != nothing
zmin, zmax = extrema(series[:marker_z])
GR.setspace(zmin, zmax, 0, 90)
end
gr_draw_markers(series, x, y, clims)
end
elseif st == :contour
zmin, zmax = gr_lims(zaxis, false)
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
zmin, zmax = clims
GR.setspace(zmin, zmax, 0, 90)
if typeof(series[:levels]) <: Array
h = series[:levels]
@@ -883,7 +988,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
# create the colorbar of contour levels
if sp[:colorbar] != :none
if cmap
gr_set_viewport_cmap(sp)
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
GR.setwindow(xmin, xmax, zmin, zmax)
@@ -908,12 +1013,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :heatmap
xmin, xmax, ymin, ymax = xy_lims
zmin, zmax = gr_lims(zaxis, true)
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
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]
@@ -923,21 +1023,26 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
round(Int, red(c) * 255) ), colors)
w, h = length(x), length(y)
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
cmap && gr_colorbar(sp)
cmap && gr_colorbar(sp, clims)
elseif st in (:path3d, :scatter3d)
# draw path
if st == :path3d
if length(x) > 1
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
GR.polyline3d(x, y, z)
for i in 1:length(x) - 1
xseg = x[i:(i + 1)]
yseg = y[i:(i + 1)]
zseg = z[i:(i + 1)]
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
GR.polyline3d(xseg, yseg, zseg)
end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
cmap && gr_colorbar(sp, clims)
end
# draw markers
if st == :scatter3d || series[:markershape] != :none
x2, y2 = unzip(map(GR.wc3towc, x, y, z))
gr_draw_markers(series, x2, y2)
gr_draw_markers(series, x2, y2, clims)
end
# TODO: replace with pie recipe
@@ -989,23 +1094,25 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.selntran(1)
elseif st == :shape
for (i,rng) in enumerate(iter_segments(series[:x], series[:y]))
for (i,rng) in enumerate(iter_segments(x, y))
if length(rng) > 1
# connect to the beginning
rng = vcat(rng, rng[1])
# get the segments
x, y = series[:x][rng], series[:y][rng]
xseg, yseg = x[rng], y[rng]
# draw the interior
gr_set_fill(_cycle(series[:fillcolor], i))
GR.fillarea(x, y)
gr_set_fill(get_fillcolor(sp, series, i))
GR.fillarea(xseg, yseg)
# draw the shapes
gr_set_line(series[:linewidth], :solid, _cycle(series[:linecolor], i))
GR.polyline(x, y)
gr_set_line(series[:linewidth], :solid, get_linecolor(sp, series, i))
GR.polyline(xseg, yseg)
end
end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
cmap && gr_colorbar(sp, clims)
elseif st == :image
@@ -1081,10 +1188,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
for series in series_list(sp)
should_add_to_legend(series) || continue
st = series[:seriestype]
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series)) #, series[:linealpha])
if st == :shape || series[:fillrange] != nothing
gr_set_fill(series[:fillcolor]) #, series[:fillalpha])
if (st == :shape || series[:fillrange] != nothing) && series[:ribbon] == nothing
gr_set_fill(get_fillcolor(sp, series)) #, series[:fillalpha])
l, r = xpos-0.07, xpos-0.01
b, t = ypos-0.4dy, ypos+0.4dy
x = [l, r, r, l, l]
+10 -6
View File
@@ -18,7 +18,8 @@ Add in functionality to Plots.jl:
const _inspectdr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
# :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
@@ -334,15 +335,18 @@ end
# ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
const gridon = InspectDR.GridRect(vmajor=true, hmajor=true)
const gridoff = InspectDR.GridRect()
const plot = sp.o
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
#No independent control of grid???
strip.grid = sp[:grid]? gridon: gridoff
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
ygrid_show = yaxis[:grid]
strip.grid = InspectDR.GridRect(
vmajor=xgrid_show, # vminor=xgrid_show,
hmajor=ygrid_show, # hminor=ygrid_show,
)
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(xaxis)
+11 -5
View File
@@ -31,6 +31,7 @@ const _pgfplots_attr = merge_with_base_supported([
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
@@ -98,7 +99,7 @@ const _pgf_series_extrastyle = KW(
:xsticks => "xcomb",
)
# PGFPlots uses the anchors to define orientations for example to align left
# PGFPlots uses the anchors to define orientations for example to align left
# one needs to use the right edge as anchor
const _pgf_annotation_halign = KW(
:center => "",
@@ -121,7 +122,7 @@ function pgf_color(grad::ColorGradient)
end
# Generates a colormap for pgfplots based on a ColorGradient
function pgf_colormap(grad::ColorGradient)
function pgf_colormap(grad::ColorGradient)
join(map(grad.colors) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
end,", ")
@@ -266,6 +267,11 @@ function pgf_axis(sp::Subplot, letter)
push!(style, "$(letter)majorticks=false")
end
# grid on or off
if axis[:grid]
push!(style, "$(letter)majorgrids = true")
end
# limits
# TODO: support zlims
if letter != :z
@@ -274,10 +280,11 @@ function pgf_axis(sp::Subplot, letter)
kw[Symbol(letter,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :auto))
if !(axis[:ticks] in (nothing, false, :none))
ticks = get_ticks(axis)
push!(style, string(letter, "tick = {", join(ticks[1],","), "}"))
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}"))
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
end
# return the style list and KW args
@@ -324,7 +331,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:title] = "$(sp[:title])"
end
sp[:grid] && push!(style, "grid = major")
if sp[:aspect_ratio] in (1, :equal)
kw[:axisEqual] = "true"
end
@@ -360,7 +366,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:colorbar] = "true"
end
# goto is needed to break out of col and series for
@goto colorbar_end
@goto colorbar_end
end
end
end
+59 -19
View File
@@ -5,7 +5,7 @@ const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
# :foreground_color_grid, :foreground_color_axis,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
@@ -19,7 +19,8 @@ const _plotly_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar, :colorbar_title,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :levels,
:ribbon, :quiver,
:orientation,
@@ -32,6 +33,8 @@ const _plotly_attr = merge_with_base_supported([
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
])
const _plotly_seriestype = [
@@ -46,6 +49,17 @@ const _plotly_marker = [
const _plotly_scale = [:identity, :log10]
is_subplot_supported(::PlotlyBackend) = true
# is_string_supported(::PlotlyBackend) = true
const _plotly_framestyles = [:box, :axes, :zerolines, :grid, :none]
const _plotly_framestyle_defaults = Dict(:semi => :box, :origin => :zerolines)
function _plotly_framestyle(style::Symbol)
if style in _plotly_framestyles
return style
else
default_style = get(_plotly_framestyle_defaults, style, :axes)
warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
default_style
end
end
# --------------------------------------------------------------------------------------
@@ -211,11 +225,19 @@ end
function plotly_axis(axis::Axis, sp::Subplot)
letter = axis[:letter]
framestyle = sp[:framestyle]
ax = KW(
:visible => framestyle != :none,
:title => axis[:guide],
:showgrid => sp[:grid],
:zeroline => false,
:ticks => "inside",
:showgrid => axis[:grid],
:gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
:gridwidth => axis[:gridlinewidth],
:zeroline => framestyle == :zerolines,
:zerolinecolor => rgba_string(axis[:foreground_color_axis]),
:showline => framestyle in (:box, :axes),
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks => axis[:tick_direction] == :out ? "outside" : "inside",
:mirror => framestyle == :box,
)
if letter in (:x,:y)
@@ -229,8 +251,8 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
ax[:tickcolor] = rgba_string(axis[:foreground_color_border])
ax[:linecolor] = rgba_string(axis[:foreground_color_border])
ax[:tickcolor] = framestyle in (:zerolines, :grid) ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# lims
lims = axis[:lims]
@@ -296,6 +318,9 @@ function plotly_layout(plt::Plot)
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
# set to supported framestyle
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
# if any(is3d, seriesargs)
if is3d(sp)
d_out[:scene] = KW(
@@ -435,7 +460,8 @@ function plotly_series(plt::Plot, series::Series)
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d)
hasfillrange = st in (:path, :scatter, :scattergl) && isa(series[:fillrange], AbstractVector)
hasfillrange = st in (:path, :scatter, :scattergl) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
# for surface types, set the data
if st in (:heatmap, :contour, :surface, :wireframe)
@@ -459,7 +485,7 @@ function plotly_series(plt::Plot, series::Series)
else
hasline ? "lines" : "none"
end
if series[:fillrange] == true || series[:fillrange] == 0
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)
@@ -550,14 +576,18 @@ function plotly_series(plt::Plot, series::Series)
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
d_out[:marker][:color] = if series[:marker_z] == nothing
rgba_string(series[:markercolor])
if series[:marker_z] == nothing
d_out[:marker][:color] = rgba_string(series[:markercolor])
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
grad = as_gradient(series[:markercolor], series[:markeralpha])
zmin, zmax = ignorenan_extrema(series[:marker_z])
zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
[rgba_string(grad[(zi - zmin) / zrange]) for zi in series[:marker_z]]
# grad = as_gradient(series[:markercolor], series[:markeralpha])
cmin, cmax = get_clims(sp)
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
d_out[:marker][:color] = [clamp(zi, cmin, cmax) for zi in series[:marker_z]]
d_out[:marker][:cmin] = cmin
d_out[:marker][:cmax] = cmax
d_out[:marker][:colorscale] = plotly_colorscale(series[:markercolor], series[:markeralpha])
d_out[:marker][:showscale] = hascolorbar(sp)
end
end
@@ -584,11 +614,21 @@ function plotly_series(plt::Plot, series::Series)
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
# series, one for series being filled to) instead of one
d_out_fillrange = copy(d_out)
d_out_fillrange[:y] = series[:fillrange]
d_out_fillrange = deepcopy(d_out)
d_out_fillrange[:showlegend] = false
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
if isa(series[:fillrange], AbstractVector)
d_out_fillrange[:y] = series[:fillrange]
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
else
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
# is the series that will do the filling
d_out_fillrange[:x], d_out_fillrange[:y] =
concatenate_fillrange(series[:x], series[:fillrange])
d_out_fillrange[:line][:width] = 0
delete!(d_out, :fill)
delete!(d_out, :fillcolor)
end
return [d_out_fillrange, d_out]
else
+87 -81
View File
@@ -17,7 +17,8 @@ const _pyplot_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
@@ -31,6 +32,9 @@ const _pyplot_attr = merge_with_base_supported([
:inset_subplots,
:dpi,
:colorbar_title,
:stride,
:framestyle,
:tick_direction,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape,
@@ -441,11 +445,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
xyargs = (st in _3dTypes ? (x,y,z) : (x,y))
# handle zcolor and get c/cmap
extrakw = KW()
needs_colorbar = hascolorbar(sp)
extrakw = if needs_colorbar || is_2tuple(sp[:clims])
vmin, vmax = get_clims(sp)
KW(:vmin => vmin, :vmax => vmax)
else
KW()
end
# holds references to any python object representing the matplotlib series
handles = []
needs_colorbar = false
discrete_colorbar_values = nothing
@@ -492,11 +501,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
:linewidth => py_dpi_scale(plt, series[:linewidth]),
:linestyle => py_linestyle(st, series[:linestyle])
)
clims = sp[:clims]
if is_2tuple(clims)
extrakw = KW()
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
if needs_colorbar
kw[:norm] = pycolors["Normalize"](; extrakw...)
end
lz = collect(series[:line_z])
@@ -526,7 +531,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
lc
end
push!(handles, handle)
needs_colorbar = true
end
a = series[:arrow]
@@ -560,18 +564,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if series[:markershape] != :none && st in (:path, :scatter, :path3d,
:scatter3d, :steppre, :steppost,
:bar)
extrakw = KW()
if series[:marker_z] == nothing
extrakw[:c] = py_color_fix(py_markercolor(series), x)
else
extrakw[:c] = convert(Vector{Float64}, series[:marker_z])
extrakw[:cmap] = py_markercolormap(series)
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
end
needs_colorbar = true
end
xyargs = if st == :bar && !isvertical(series)
(y, x)
@@ -621,11 +618,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
if st == :hexbin
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
end
handle = ax[:hexbin](x, y;
label = series[:label],
zorder = series[:series_plotindex],
@@ -636,18 +628,10 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw...
)
push!(handles, handle)
needs_colorbar = true
end
if st in (:contour, :contour3d)
z = transpose_z(series, z.surf)
needs_colorbar = true
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
end
if st == :contour3d
extrakw[:extend3d] = true
@@ -685,11 +669,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
z = transpose_z(series, z)
if st == :surface
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
end
if series[:fill_z] != nothing
# the surface colors are different than z-value
extrakw[:facecolors] = py_shading(series[:fillcolor], transpose_z(series, series[:fill_z].surf))
@@ -697,13 +676,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
else
extrakw[:cmap] = py_fillcolormap(series)
end
needs_colorbar = true
end
handle = ax[st == :surface ? :plot_surface : :plot_wireframe](x, y, z;
label = series[:label],
zorder = series[:series_plotindex],
rstride = 1,
cstride = 1,
rstride = series[:stride][1],
cstride = series[:stride][2],
linewidth = py_dpi_scale(plt, series[:linewidth]),
edgecolor = py_linecolor(series),
extrakw...
@@ -720,14 +698,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat) # where to draw the contour plane
)
push!(handles, handle)
needs_colorbar = true
end
end
# no colorbar if we are creating a surface LightSource
if haskey(extrakw, :facecolors)
needs_colorbar = false
end
elseif typeof(z) <: AbstractVector
# tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots)
@@ -745,7 +718,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw...
)
push!(handles, handle)
needs_colorbar = true
else
error("Unsupported z type $(typeof(z)) for seriestype=$st")
end
@@ -785,11 +757,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
discrete_colorbar_values = dvals
end
clims = sp[:clims]
zmin, zmax = ignorenan_extrema(z)
extrakw[:vmin] = (is_2tuple(clims) && isfinite(clims[1])) ? clims[1] : zmin
extrakw[:vmax] = (is_2tuple(clims) && isfinite(clims[2])) ? clims[2] : zmax
handle = ax[:pcolormesh](x, y, py_mask_nans(z);
label = series[:label],
zorder = series[:series_plotindex],
@@ -798,7 +765,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw...
)
push!(handles, handle)
needs_colorbar = true
end
if st == :shape
@@ -841,30 +807,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# # smoothing
# handleSmooth(plt, ax, series, series[:smooth])
# add the colorbar legend
if needs_colorbar && sp[:colorbar] != :none
# add keyword args for a discrete colorbar
handle = handles[end]
kw = KW()
if discrete_colorbar_values != nothing
locator, formatter = get_locator_and_formatter(discrete_colorbar_values)
# kw[:values] = 1:length(discrete_colorbar_values)
kw[:values] = sp[:zaxis][:continuous_values]
kw[:ticks] = locator
kw[:format] = formatter
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
end
# create and store the colorbar object (handle) and the axis that it is drawn on.
# note: the colorbar axis is positioned independently from the subplot axis
fig = plt.o
cbax = fig[:add_axes]([0.8,0.1,0.03,0.8], label = string(gensym()))
cb = fig[:colorbar](handle; cax = cbax, kw...)
cb[:set_label](sp[:colorbar_title])
sp.attr[:cbar_handle] = cb
sp.attr[:cbar_ax] = cbax
end
# handle area filling
fillrange = series[:fillrange]
if fillrange != nothing && st != :contour
@@ -962,21 +904,22 @@ function py_set_scale(ax, axis::Axis)
elseif scale == :log10
10
end
kw[Symbol(:linthresh,letter)] = NaNMath.max(1e-16, py_compute_axis_minval(axis))
kw[Symbol(:linthresh,letter)] = NaNMath.min(1e-16, py_compute_axis_minval(axis))
"symlog"
end
func(arg; kw...)
end
function py_set_axis_colors(ax, a::Axis)
function py_set_axis_colors(sp, ax, a::Axis)
for (loc, spine) in ax[:spines]
spine[:set_color](py_color(a[:foreground_color_border]))
end
axissym = Symbol(a[:letter], :axis)
if haskey(ax, axissym)
tickcolor = sp[:framestyle] == :zerolines ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis])
ax[:tick_params](axis=string(a[:letter]), which="both",
colors=py_color(a[:foreground_color_axis]),
colors=tickcolor,
labelcolor=py_color(a[:foreground_color_text]))
ax[axissym][:label][:set_color](py_color(a[:foreground_color_guide]))
end
@@ -1038,6 +981,58 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
# ax[:set_title](sp[:title], loc = loc)
end
# add the colorbar legend
if hascolorbar(sp)
# add keyword args for a discrete colorbar
slist = series_list(sp)
colorbar_series = slist[findfirst(hascolorbar.(slist))]
handle = colorbar_series[:serieshandle][end]
kw = KW()
if !isempty(sp[:zaxis][:discrete_values]) && colorbar_series[:seriestype] == :heatmap
locator, formatter = get_locator_and_formatter(sp[:zaxis][:discrete_values])
# kw[:values] = 1:length(sp[:zaxis][:discrete_values])
kw[:values] = sp[:zaxis][:continuous_values]
kw[:ticks] = locator
kw[:format] = formatter
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
end
# create and store the colorbar object (handle) and the axis that it is drawn on.
# note: the colorbar axis is positioned independently from the subplot axis
fig = plt.o
cbax = fig[:add_axes]([0.8,0.1,0.03,0.8], label = string(gensym()))
cb = fig[:colorbar](handle; cax = cbax, kw...)
cb[:set_label](sp[:colorbar_title])
sp.attr[:cbar_handle] = cb
sp.attr[:cbar_ax] = cbax
end
# framestyle
if !ispolar(sp) && !is3d(sp)
if sp[:framestyle] == :semi
intensity = 0.5
ax[:spines]["right"][:set_alpha](intensity)
ax[:spines]["top"][:set_alpha](intensity)
ax[:spines]["right"][:set_linewidth](intensity)
ax[:spines]["top"][:set_linewidth](intensity)
elseif sp[:framestyle] in (:axes, :origin)
ax[:spines]["right"][:set_visible](false)
ax[:spines]["top"][:set_visible](false)
if sp[:framestyle] == :origin
ax[:spines]["bottom"][:set_position]("zero")
ax[:spines]["left"][:set_position]("zero")
end
elseif sp[:framestyle] in (:grid, :none, :zerolines)
for (loc, spine) in ax[:spines]
spine[:set_visible](false)
end
if sp[:framestyle] == :zerolines
ax[:axhline](y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = 0.75)
ax[:axvline](x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = 0.75)
end
end
end
# axis attributes
for letter in (:x, :y, :z)
axissym = Symbol(letter, :axis)
@@ -1052,7 +1047,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
py_set_scale(ax, axis)
py_set_lims(ax, axis)
py_set_ticks(ax, get_ticks(axis), letter)
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(ticks) > 1
ticks[2][ticks[1] .== 0] = ""
end
py_set_ticks(ax, ticks, letter)
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
ax[Symbol("set_", letter, "label")](axis[:guide])
if get(axis.d, :flip, false)
ax[Symbol("invert_", letter, "axis")]()
@@ -1064,12 +1065,16 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
lab[:set_family](axis[:tickfont].family)
lab[:set_rotation](axis[:rotation])
end
if sp[:grid]
fgcolor = py_color(sp[:foreground_color_grid])
pyaxis[:grid](true, color = fgcolor, linestyle = ":")
if axis[:grid] && !(ticks in (:none, nothing, false))
fgcolor = py_color(axis[:foreground_color_grid])
pyaxis[:grid](true,
color = fgcolor,
linestyle = py_linestyle(:line, axis[:gridstyle]),
linewidth = axis[:gridlinewidth],
alpha = axis[:gridalpha])
ax[:set_axisbelow](true)
end
py_set_axis_colors(ax, axis)
py_set_axis_colors(sp, ax, axis)
end
# aspect ratio
@@ -1083,6 +1088,7 @@ 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]))
end
py_drawfig(fig)
end
+28 -1
View File
@@ -22,6 +22,13 @@ immutable Shape
# end
# end
end
"""
Shape(x, y)
Shape(vertices)
Construct a polygon to be plotted
"""
Shape(verts::AVec) = Shape(unzip(verts)...)
Shape(s::Shape) = deepcopy(s)
@@ -32,6 +39,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
#deprecated
@deprecate shape_coords coords
"return the vertex points from a Shape or Segments object"
function coords(shape::Shape)
shape.x, shape.y
end
@@ -156,6 +164,7 @@ Shape(k::Symbol) = deepcopy(_shapes[k])
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
"return the centroid of a Shape"
function center(shape::Shape)
x, y = coords(shape)
n = length(x)
@@ -189,6 +198,7 @@ function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
scale!(shapecopy, x, y, c)
end
"translate a Shape in space"
function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape)
for i=1:length(sx)
@@ -227,6 +237,7 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
shape
end
"rotate an object in space"
function rotate(shape::Shape, Θ::Real, c = center(shape))
shapecopy = deepcopy(shape)
rotate!(shapecopy, Θ, c)
@@ -331,6 +342,11 @@ immutable PlotText
end
PlotText(str) = PlotText(string(str), font())
"""
text(string, args...)
Create a PlotText object wrapping a string with font info, for plot annotations
"""
text(t::PlotText) = t
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
@@ -350,6 +366,11 @@ immutable Stroke
style
end
"""
stroke(args...; alpha = nothing)
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing)
width = 1
color = :black
@@ -597,6 +618,12 @@ immutable Arrow
headwidth::Float64
end
"""
arrow(args...)
Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
`side` (`:head`, `:tail` or `:both`), `headlength` and `headwidth`
"""
function arrow(args...)
style = :simple
side = :head
@@ -652,7 +679,7 @@ immutable Formatted{T}
end
# -----------------------------------------------------------------------
"create a BezierCurve for plotting"
type BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T}
end
+31 -3
View File
@@ -155,7 +155,7 @@ PlotExample("Subplots",
""",
[:(begin
l = @layout([a{0.1h}; b [c;d e]])
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=false)
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=:none)
end)]
),
@@ -288,9 +288,10 @@ PlotExample("Heatmap, categorical axes, and aspect_ratio",
PlotExample("Layouts, margins, label rotation, title location",
"",
[:(begin
using Plots.PlotMeasures # for Measures, e.g. mm and px
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
title_location=:left, left_margin=[20mm 0mm],
bottom_margin=50px, xrotation=60)
bottom_margin=10px, xrotation=60)
end)]
),
@@ -321,7 +322,7 @@ PlotExample("Animation with subplots",
),
PlotExample("Spy",
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`",
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`.",
[:(begin
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
@@ -329,6 +330,26 @@ PlotExample("Spy",
end)]
),
PlotExample("Magic grid argument",
"The grid lines can be modified individually for each axis with the magic `grid` argument.",
[:(begin
x = rand(10)
p1 = plot(x, title = "Default looks")
p2 = plot(x, grid = (:y, :olivedrab, :dot, 1, 0.9), title = "Modified y grid")
p3 = plot(deepcopy(p2), title = "Add x grid")
xgrid!(p3, :on, :cadetblue, 2, :dashdot, 0.4)
plot(p1, p2, p3, layout = (1, 3), label = "", fillrange = 0, fillalpha = 0.3)
end)]
),
PlotExample("Framestyle",
"The style of the frame/axes of a (sub)plot can be changed with the `framestyle` attribute. The default framestyle is `:axes`.",
[:(begin
histogram(fill(randn(1000), 5), framestyle = [:box :semi :axes :grid :none],
title = [":box" ":semi" ":axes" ":grid" ":none"], color = RowVector(1:5), layout = 5, label = "")
end)]
),
]
# ---------------------------------------------------------------------------------
@@ -348,6 +369,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
end
# generate all plots and create a dict mapping idx --> plt
"""
test_examples(pkgname[, idx]; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing
Run the `idx` test example for a given backend, or all examples if `idx`
is not specified.
"""
function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing)
Plots._debugMode.on = debug
+12 -4
View File
@@ -1,10 +1,6 @@
# NOTE: (0,0) is the top-left !!!
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm
@@ -133,7 +129,12 @@ make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h
make_measure_vert(m::Measure) = m
"""
bbox(x, y, w, h [,originargs...])
bbox(layout)
Create a bounding box for plotting
"""
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
oargs = vcat(oarg1, originargs...)
orighor = :left
@@ -253,6 +254,13 @@ type GridLayout <: AbstractLayout
attr::KW
end
"""
grid(args...; kw...)
Create a grid layout for subplots. `args` specify the dimensions, e.g.
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two
columns of different width.
"""
grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout(dims...;
+14 -1
View File
@@ -39,7 +39,7 @@ ps(fn::AbstractString) = ps(current(), fn)
function eps(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "eps")
io = open(fn, "w")
writemime(io, MIME("image/eps"), plt)
show(io, MIME("image/eps"), plt)
close(io)
end
eps(fn::AbstractString) = eps(current(), fn)
@@ -97,6 +97,13 @@ function addExtension(fn::AbstractString, ext::AbstractString)
end
end
"""
savefig([plot,] filename)
Save a Plot (the current plot if `plot` is not passed) to file. The file
type is inferred from the file extension. All backends support png and pdf
file types, some also support svg, ps, eps, html and tex.
"""
function savefig(plt::Plot, fn::AbstractString)
# get the extension
@@ -119,7 +126,11 @@ savefig(fn::AbstractString) = savefig(current(), fn)
# ---------------------------------------------------------
"""
gui([plot])
Display a plot using the backends' gui window
"""
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
# IJulia only... inline display
@@ -198,6 +209,7 @@ for mime in keys(_mimeformats)
end
end
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
@@ -266,6 +278,7 @@ using Requires
show(io, MIME("text/html"), plt)
end
ENV["MPLBACKEND"] = "Agg"
set_ijulia_output("text/html")
end
end
+21 -19
View File
@@ -60,29 +60,26 @@ function _process_userrecipes(plt::Plot, d::KW, args)
args = _preprocess_args(d, args, still_to_process)
# for plotting recipes, swap out the args and update the parameter dictionary
# we are keeping a queue of series that still need to be processed.
# we are keeping a stack of series that still need to be processed.
# each pass through the loop, we pop one off and apply the recipe.
# the recipe will return a list a Series objects... the ones that are
# finished (no more args) get added to the kw_list, and the rest go into the queue
# for processing.
# finished (no more args) get added to the kw_list, the ones that are not
# are placed on top of the stack and are then processed further.
kw_list = KW[]
while !isempty(still_to_process)
# grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes)
# grab the first in line to be processed and either add it to the kw_list or
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
# for further processing.
next_series = shift!(still_to_process)
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
for recipedata in rd_list
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(recipedata) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
end
if isempty(recipedata.args)
_process_userrecipe(plt, kw_list, recipedata)
else
# args are non-empty, so there's still processing to do... add it back to the queue
push!(still_to_process, recipedata)
end
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(next_series) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
end
if isempty(next_series.args)
_process_userrecipe(plt, kw_list, next_series)
else
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
prepend!(still_to_process,rd_list)
end
end
@@ -213,7 +210,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# TODO: init subplots here
_update_plot_args(plt, d)
if !plt.init
plt.o = _create_backend_figure(plt)
plt.o = Base.invokelatest(_create_backend_figure, plt)
# create the layout and subplots from the inputs
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
@@ -367,6 +364,11 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
expand_extrema!(sp, d)
end
# expand for zerolines (axes through origin)
if sp[:framestyle] in (:origin, :zerolines)
expand_extrema!(sp[:xaxis], 0.0)
expand_extrema!(sp[:yaxis], 0.0)
end
end
function _add_the_series(plt, sp, d)
+5 -1
View File
@@ -6,6 +6,10 @@ const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
"""
current()
Returns the Plot object for the current plot
"""
function current()
if isplotnull()
error("No current plot/subplot")
@@ -80,7 +84,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
# TODO: replace this with proper processing from a merged user_attr KW
# update plot args, first with existing plots, then override with d
for p in plts
_update_plot_args(plt, p.attr)
_update_plot_args(plt, copy(p.attr))
plt.n += p.n
end
_update_plot_args(plt, d)
+6
View File
@@ -14,6 +14,12 @@ function lookup_aliases(attrtype, attribute)
error("There is no attribute named $attribute in $attrtype")
end
"""
plotattr([attr])
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
The information is the same as that given on https://juliaplots.github.io/attributes/.
"""
function plotattr()
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
end
+59 -51
View File
@@ -79,7 +79,7 @@ function hvline_limits(axis::Axis)
end
@recipe function f(::Type{Val{:hline}}, x, y, z)
xmin, xmax = hvline_limits(d[:subplot][:xaxis])
xmin, xmax = hvline_limits(plotattributes[:subplot][:xaxis])
n = length(y)
newx = repmat(Float64[xmin, xmax, NaN], n)
newy = vec(Float64[yi for i=1:3,yi=y])
@@ -91,7 +91,7 @@ end
@deps hline path
@recipe function f(::Type{Val{:vline}}, x, y, z)
ymin, ymax = hvline_limits(d[:subplot][:yaxis])
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)
@@ -123,11 +123,11 @@ end
# create a path from steps
@recipe function f(::Type{Val{:steppre}}, x, y, z)
d[:x], d[:y] = make_steps(x, y, :steppre)
plotattributes[:x], plotattributes[:y] = make_steps(x, y, :steppre)
seriestype := :path
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
@@ -144,11 +144,11 @@ end
# create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z)
d[:x], d[:y] = make_steps(x, y, :steppost)
plotattributes[:x], plotattributes[:y] = make_steps(x, y, :steppost)
seriestype := :path
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
@@ -170,9 +170,9 @@ end
# create vertical line segments from fill
@recipe function f(::Type{Val{:sticks}}, x, y, z)
n = length(x)
fr = d[:fillrange]
fr = plotattributes[:fillrange]
if fr == nothing
yaxis = d[:subplot][:yaxis]
yaxis = plotattributes[:subplot][:yaxis]
fr = if yaxis[:scale] == :identity
0.0
else
@@ -191,7 +191,7 @@ end
seriestype := :path
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
@@ -224,7 +224,7 @@ end
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30)
args = z != nothing ? (x,y,z) : (x,y)
newx, newy = zeros(0), zeros(0)
fr = d[:fillrange]
fr = plotattributes[:fillrange]
newfr = fr != nothing ? zeros(0) : nothing
newz = z != nothing ? zeros(0) : nothing
# lz = d[:line_z]
@@ -274,9 +274,9 @@ end
# create a bar plot as a filled step function
@recipe function f(::Type{Val{:bar}}, x, y, z)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(d, x, y)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y)
nx, ny = length(procx), length(procy)
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi=procx]
procx = if nx == ny
cv
@@ -287,15 +287,15 @@ end
end
# compute half-width of bars
bw = d[:bar_width]
bw = plotattributes[:bar_width]
hw = if bw == nothing
0.5ignorenan_mean(diff(procx))
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx)))
else
Float64[0.5_cycle(bw,i) for i=1:length(procx)]
end
# make fillto a vector... default fills to 0
fillto = d[:fillrange]
fillto = plotattributes[:fillrange]
if fillto == nothing
fillto = 0
end
@@ -320,7 +320,7 @@ end
expand_extrema!(axis, widen(ignorenan_extrema(xseg.pts)...))
# switch back
if !isvertical(d)
if !isvertical(plotattributes)
xseg, yseg = yseg, xseg
end
@@ -389,8 +389,8 @@ end
@recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
if (d[:bar_width] == nothing)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
if (plotattributes[:bar_width] == nothing)
bar_width := diff(edge)
end
x := _bin_centers(edge)
@@ -402,7 +402,7 @@ end
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
xerror := diff(edge)/2
x := _bin_centers(edge)
y := weights
@@ -465,17 +465,17 @@ end
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
axis = d[:subplot][Plots.isvertical(d) ? :xaxis : :yaxis]
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(d)
if !isvertical(plotattributes)
xpts, ypts = ypts, xpts
end
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := _bin_centers(edge)
@@ -497,33 +497,40 @@ end
end
Plots.@deps stepbins path
wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto)
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
_iqr(v) = quantile(v, 0.75) - quantile(v, 0.25)
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
n_samples = length(linearindices(first(vs)))
# Estimator for number of samples in one row/column of bins along each axis:
n = max(1, n_samples^(1/N))
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
nd = n_samples^(1/(2+N))
nd = N == 2 ? nd / (1-cor(first(vs), last(vs))^2)^(3//8) : nd # the >2-dimensional case does not have a nice solution to correlations
v = vs[dim]
if mode == :auto
30
elseif mode == :sqrt # Square-root choice
_cl(sqrt(n))
mode = :fd
end
if mode == :sqrt # Square-root choice
_cl(sqrt(n_samples))
elseif mode == :sturges # Sturges' formula
_cl(log2(n)) + 1
_cl(log2(n_samples) + 1)
elseif mode == :rice # Rice Rule
_cl(2 * n^(1/3))
_cl(2 * nd)
elseif mode == :scott # Scott's normal reference rule
_cl(_span(v) / (3.5 * std(v) / n^(1/3)))
_cl(_span(v) / (3.5 * std(v) / nd))
elseif mode == :fd # FreedmanDiaconis rule
_cl(_span(v) / (2 * _iqr(v) / n^(1/3)))
_cl(_span(v) / (2 * _iqr(v) / nd))
elseif mode == :wand
wand_edges(v) # this makes this function not type stable, but the type instability does not propagate
else
error("Unknown auto-binning mode $mode")
end::Int
end
end
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) = StatsBase.histrange(vs[dim], binning, :left)
@@ -550,13 +557,13 @@ end
@recipe function f(::Type{Val{:histogram}}, x, y, z)
seriestype := :barhist
seriestype := length(y) > 1e6 ? :stephist : :barhist
()
end
@deps histogram barhist
@recipe function f(::Type{Val{:barhist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :barbins
@@ -565,7 +572,7 @@ end
@deps barhist barbins
@recipe function f(::Type{Val{:stephist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :stepbins
@@ -574,7 +581,7 @@ end
@deps stephist stepbins
@recipe function f(::Type{Val{:scatterhist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :scatterbins
@@ -590,11 +597,11 @@ end
:bar => :barbins, :scatter => :scatterbins, :step => :stepbins,
:steppost => :stepbins # :step can be mapped to :steppost in pre-processing
)
seriestype := get(st_map, d[:seriestype], d[:seriestype])
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
if d[:seriestype] == :scatterbins
if plotattributes[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, h.edges[1], h.weights)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, h.edges[1], h.weights)
xerror --> diff(h.edges[1])/2
seriestype := :scatter
(Plots._bin_centers(edge), weights)
@@ -641,7 +648,7 @@ Plots.@deps bins2d heatmap
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
h = _make_hist((x, y), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((x, y), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.edges[2]
z := Surface(h.weights)
@@ -662,7 +669,7 @@ end
@recipe function f(::Type{Val{:scatter3d}}, x, y, z)
seriestype := :path3d
if d[:markershape] == :none
if plotattributes[:markershape] == :none
markershape := :circle
end
linewidth := 0
@@ -725,17 +732,17 @@ end
# we will create a series of path segments, where each point represents one
# side of an errorbar
@recipe function f(::Type{Val{:yerror}}, x, y, z)
error_style!(d)
error_style!(plotattributes)
markershape := :hline
d[:x], d[:y] = error_coords(d[:x], d[:y], error_zipit(d[:yerror]))
plotattributes[:x], plotattributes[:y] = error_coords(plotattributes[:x], plotattributes[:y], error_zipit(plotattributes[:yerror]))
()
end
@deps yerror path
@recipe function f(::Type{Val{:xerror}}, x, y, z)
error_style!(d)
error_style!(plotattributes)
markershape := :vline
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
plotattributes[:y], plotattributes[:x] = error_coords(plotattributes[:y], plotattributes[:x], error_zipit(plotattributes[:xerror]))
()
end
@deps xerror path
@@ -834,9 +841,9 @@ end
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
@recipe function f(::Type{Val{:quiver}}, x, y, z)
if :arrow in supported_attrs()
quiver_using_arrows(d)
quiver_using_arrows(plotattributes)
else
quiver_using_hack(d)
quiver_using_hack(plotattributes)
end
()
end
@@ -847,6 +854,7 @@ end
# TODO: move OHLC to PlotRecipes finance.jl
"Represent Open High Low Close data (used in finance)"
type OHLC{T<:Real}
open::T
high::T
@@ -940,10 +948,10 @@ end
rs, cs, zs = findnz(z.surf)
xlim := ignorenan_extrema(cs)
ylim := ignorenan_extrema(rs)
if d[:markershape] == :none
if plotattributes[:markershape] == :none
markershape := :circle
end
if d[:markersize] == default(:markersize)
if plotattributes[:markersize] == default(:markersize)
markersize := 1
end
markerstrokewidth := 0
+107 -32
View File
@@ -10,6 +10,9 @@ const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
# unknown
convertToAnyVector(x, d::KW) = error("No user recipe defined for $(typeof(x))")
# missing
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
@@ -125,15 +128,15 @@ immutable SliceIt end
z = z.data
end
xs, _ = convertToAnyVector(x, d)
ys, _ = convertToAnyVector(y, d)
zs, _ = convertToAnyVector(z, d)
xs, _ = convertToAnyVector(x, plotattributes)
ys, _ = convertToAnyVector(y, plotattributes)
zs, _ = convertToAnyVector(z, plotattributes)
fr = pop!(d, :fillrange, nothing)
fr = pop!(plotattributes, :fillrange, nothing)
fillranges, _ = if typeof(fr) <: Number
([fr],nothing)
else
convertToAnyVector(fr, d)
convertToAnyVector(fr, plotattributes)
end
mf = length(fillranges)
@@ -145,7 +148,7 @@ immutable SliceIt end
if mx > 0 && my > 0 && mz > 0
for i in 1:max(mx, my, mz)
# add a new series
di = copy(d)
di = copy(plotattributes)
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
@@ -171,6 +174,7 @@ _apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
# This sort of recipe should return a pair of functions... one to convert to number,
# and one to format tick values.
function _apply_type_recipe(d, v::AbstractArray)
isempty(v) && return Float64[]
args = RecipesBase.apply_recipe(d, typeof(v[1]), v[1])[1].args
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
numfunc, formatter = args
@@ -202,11 +206,11 @@ _apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
# handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z)
did_replace = false
newx = _apply_type_recipe(d, x)
newx = _apply_type_recipe(plotattributes, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
y === newy || (did_replace = true)
newz = _apply_type_recipe(d, z)
newz = _apply_type_recipe(plotattributes, z)
z === newz || (did_replace = true)
if did_replace
newx, newy, newz
@@ -216,9 +220,9 @@ _apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
end
@recipe function f(x, y)
did_replace = false
newx = _apply_type_recipe(d, x)
newx = _apply_type_recipe(plotattributes, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
y === newy || (did_replace = true)
if did_replace
newx, newy
@@ -227,7 +231,7 @@ end
end
end
@recipe function f(y)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
if y !== newy
newy
else
@@ -240,7 +244,7 @@ end
@recipe function f(v1, v2, v3, v4, vrest...)
did_replace = false
newargs = map(v -> begin
newv = _apply_type_recipe(d, v)
newv = _apply_type_recipe(plotattributes, v)
if newv !== v
did_replace = true
end
@@ -267,13 +271,13 @@ function wrap_surfaces(d::KW)
end
end
@recipe f(n::Integer) = is3d(get(d,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
# return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f{T<:Union{Integer,AbstractFloat}}(mat::AMat{T})
if all3D(d)
if all3D(plotattributes)
n,m = size(mat)
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Surface(mat)
else
SliceIt, nothing, mat, nothing
@@ -282,10 +286,10 @@ end
# if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface
@recipe function f{T<:AbstractMatrix}(fmt::Formatted{T})
if all3D(d)
if all3D(plotattributes)
mat = fmt.data
n,m = size(mat)
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
else
SliceIt, nothing, fmt, nothing
@@ -325,7 +329,7 @@ end
else
seriestype := :heatmap
yflip --> true
z, d[:fillcolor] = replace_image_with_heatmap(mat)
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, 1:m, 1:n, Surface(z)
end
end
@@ -355,15 +359,35 @@ end
# function without range... use the current range of the x-axis
@recipe function f{F<:Function}(f::FuncOrFuncs{F})
plt = d[:plot_object]
plt = plotattributes[:plot_object]
xmin, xmax = try
axis_limits(plt[1][:xaxis])
catch
-5, 5
xm = tryrange(f, [-5,-1,0,0.01])
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
end
f, xmin, xmax
end
# try some intervals over which the function may be defined
function tryrange(F::AbstractArray, vec)
rets = [tryrange(f, vec) for f in F] # get the preferred for each
maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all)
rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there
rets[1]
end
function tryrange(F, vec)
for v in vec
try
tmp = F(v)
return v
catch
end
end
error("$F is not a Function, or is not defined at any of the values $vec")
end
#
# # --------------------------------------------------------------------
# # 2 arguments
@@ -404,7 +428,7 @@ end
# seriestype := :path3d
# end
# end
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, x, y, z
end
@@ -414,7 +438,7 @@ end
@recipe function f(x::AVec, y::AVec, zf::Function)
# x = X <: Number ? sort(x) : x
# y = Y <: Number ? sort(y) : y
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
end
@@ -422,10 +446,10 @@ end
# # surface-like... matrix grid
@recipe function f(x::AVec, y::AVec, z::AMat)
if !like_surface(get(d, :seriestype, :none))
d[:seriestype] = :contour
if !like_surface(get(plotattributes, :seriestype, :none))
plotattributes[:seriestype] = :contour
end
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, x, y, Surface(z)
end
@@ -477,7 +501,7 @@ end
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(d,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
@@ -509,13 +533,64 @@ end
# nothing
# end
splittable_kw(key, val, lengthGroup) = false
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
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 groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
fill!(y_mat, def_val)
for i in 1:length(groupby.groupLabels)
xi = x[groupby.groupIds[i]]
yi = y[groupby.groupIds[i]]
y_mat[getindex.(x_ind, xi), i] = yi
end
return y_mat
end
groupedvec2mat(x_ind, x, y::Tuple, groupby) = Tuple(groupedvec2mat(x_ind, x, v, groupby) for v in y)
group_as_matrix(t) = false
# split the group into 1 series per group, and set the label and idxfilter for each
@recipe function f(groupby::GroupBy, args...)
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
idxfilter --> groupby.groupIds[i]
args
lengthGroup = maximum(union(groupby.groupIds...))
if !(group_as_matrix(args[1]))
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
idxfilter --> groupby.groupIds[i]
for (key,val) in plotattributes
if splittable_kw(key, val, lengthGroup)
:($key) := split_kw(key, val, groupby.groupIds[i])
end
end
args
end
end
else
g = args[1]
if length(g.args) == 1
x = zeros(Int64, lengthGroup)
for indexes in groupby.groupIds
x[indexes] = 1:length(indexes)
end
last_args = g.args
else
x = g.args[1]
last_args = g.args[2:end]
end
x_u = unique(x)
x_ind = Dict(zip(x_u, 1:length(x_u)))
for (key,val) in plotattributes
if splittable_kw(key, val, lengthGroup)
:($key) := groupedvec2mat(x_ind, x, val, groupby)
end
end
label --> reshape(groupby.groupLabels, 1, :)
typeof(g)((x_u, (groupedvec2mat(x_ind, x, arg, groupby, NaN) for arg in last_args)...))
end
end
+5
View File
@@ -13,6 +13,11 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
)
end
"""
plotarea(subplot)
Return the bounding box of a subplot
"""
plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
+4
View File
@@ -1,4 +1,8 @@
"""
theme(s::Symbol)
Specify the colour theme for plots.
"""
function theme(s::Symbol; kw...)
# reset?
if s == :none || s == :default
+108 -2
View File
@@ -137,7 +137,7 @@ function imageHack(d::KW)
end
# ---------------------------------------------------------------
"Build line segments for plotting"
type Segments{T}
pts::Vector{T}
end
@@ -185,6 +185,7 @@ type SegmentsIterator
args::Tuple
n::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
@@ -495,14 +496,42 @@ function make_fillrange_from_ribbon(kw::KW)
rib1, rib2 = -first(rib), last(rib)
# kw[:ribbon] = nothing
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
(get(kw, :fillalpha, nothing) == nothing) && (kw[:fillalpha] = 0.5)
end
#turn tuple of fillranges to one path
function concatenate_fillrange(x,y::Tuple)
rib1, rib2 = first(y), last(y)
yline = vcat(rib1,(rib2)[end:-1:1])
xline = vcat(x,x[end:-1:1])
return xline, yline
end
function get_sp_lims(sp::Subplot, letter::Symbol)
axis_limits(sp[Symbol(letter, :axis)])
end
"""
xlims([plt])
Returns the x axis limits of the current plot or subplot
"""
xlims(sp::Subplot) = get_sp_lims(sp, :x)
"""
ylims([plt])
Returns the y axis limits of the current plot or subplot
"""
ylims(sp::Subplot) = get_sp_lims(sp, :y)
"""
zlims([plt])
Returns the z axis limits of the current plot or subplot
"""
zlims(sp::Subplot) = get_sp_lims(sp, :z)
xlims(plt::Plot, sp_idx::Int = 1) = xlims(plt[sp_idx])
ylims(plt::Plot, sp_idx::Int = 1) = ylims(plt[sp_idx])
zlims(plt::Plot, sp_idx::Int = 1) = zlims(plt[sp_idx])
@@ -510,6 +539,83 @@ xlims(sp_idx::Int = 1) = xlims(current(), sp_idx)
ylims(sp_idx::Int = 1) = ylims(current(), sp_idx)
zlims(sp_idx::Int = 1) = zlims(current(), sp_idx)
function get_clims(sp::Subplot)
zmin, zmax = Inf, -Inf
for series in series_list(sp)
for vals in (series[:z], series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Real)
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals.surf)...)
elseif (vals != nothing) && (eltype(vals) <: Real)
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...)
end
end
end
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
return zmin < zmax ? (zmin, zmax) : (0.0, 0.0)
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)
if series[:marker_z] != nothing || series[:line_z] != nothing || series[:fill_z] != nothing
hascbar = true
end
# no colorbar if we are creating a surface LightSource
if xor(st == :surface, series[:fill_z] != nothing)
hascbar = true
end
return hascbar
end
function hascolorbar(sp::Subplot)
cbar = sp[:colorbar]
hascbar = false
if cbar != :none
for series in series_list(sp)
if hascolorbar(series)
hascbar = true
end
end
end
hascbar
end
function get_linecolor(sp::Subplot, series::Series, i::Int = 1)
lc = series[:linecolor]
lz = series[:line_z]
if lz == nothing
isa(lc, ColorGradient) ? lc : _cycle(lc, i)
else
cmin, cmax = get_clims(sp)
grad = isa(lc, ColorGradient) ? lc : cgrad()
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
function get_fillcolor(sp::Subplot, series::Series, i::Int = 1)
fc = series[:fillcolor]
fz = series[:fill_z]
lz = series[:line_z]
if fz == nothing && lz == nothing
isa(fc, ColorGradient) ? fc : _cycle(fc, i)
else
cmin, cmax = get_clims(sp)
grad = isa(fc, ColorGradient) ? fc : cgrad()
if fz != nothing
grad[clamp((_cycle(fz, i) - cmin) / (cmax - cmin), 0, 1)]
elseif lz != nothing
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
end
# ---------------------------------------------------------------
makekw(; kw...) = KW(kw)
@@ -536,7 +642,7 @@ allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
"""
Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example:
```
with(:gadfly, size=(400,400), type=:histogram) do
with(:gr, size=(400,400), type=:histogram) do
plot(rand(10))
plot(rand(10))
end
+3 -2
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.12.1"
const _current_plots_version = v"0.12.4"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
@@ -42,7 +42,8 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
fn = "ref$idx.png"
# firgure out version info
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
vns = filter(x->x[1] != '.', readdir(refdir))
versions = sort(VersionNumber.(vns), rev = true)
versions = filter(v -> v <= _current_plots_version, versions)
# @show refdir fn versions
+4
View File
@@ -8,6 +8,7 @@ default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2
@testset "GR" begin
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
@@ -128,6 +129,9 @@ end
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
end
@testset "NoFail" begin
histogram([1, 0, 0, 0, 0, 0])
end
# tests for preprocessing recipes