Compare commits

..
372 Commits
Author SHA1 Message Date
Michael Krabbe BorregaardandGitHub acfb14a1f5 Merge pull request #1289 from mkborregaard/master
update news
2017-12-07 13:11:03 +01:00
Michael K. Borregaard 6a3495819a update news 2017-12-07 13:10:26 +01:00
Michael Krabbe BorregaardandGitHub bf6e8d3c1f Merge pull request #1288 from mkborregaard/add-scatterpath
added scatterpath series recipe
2017-12-07 12:04:08 +01:00
Michael Krabbe BorregaardandGitHub 66f08cc1a3 fix typo on docstring 2017-12-07 08:52:09 +01:00
Michael Krabbe BorregaardandGitHub 470012501b Merge pull request #1286 from mforets/patch-1
say how to get the list of attributes in `?plot`
2017-12-07 08:51:19 +01:00
Marcelo ForetsandGitHub 986bd02e5e Update plot.jl 2017-12-06 22:33:47 -03:00
Michael K. Borregaard 9b8510ab3e added scatterpath series recipe 2017-12-06 23:19:35 +01:00
Marcelo ForetsandGitHub 0db9710e0f say how to get the list of attributes in ?plot 2017-12-06 17:46:35 -03:00
Michael Krabbe BorregaardandGitHub 7f231057fd Merge pull request #1284 from JuliaPlots/tbreloff-patch-1
change author section
2017-12-06 07:01:26 +01:00
Tom BreloffandGitHub bb687e47cc change author section 2017-12-05 21:14:08 -05:00
Michael Krabbe BorregaardandGitHub df63530b89 Merge pull request #1282 from wkearn/wsk/scale-fix
Update iterator properly in _subplot_setup
2017-12-05 20:44:08 +01:00
Daniel SchwabenederandGitHub 34dedd36e6 Merge pull request #1281 from hayatoikoma/fix_grayimg
Fix the display of an grayscale image for image-nonsupported backends
2017-12-05 19:43:38 +01:00
Will Kearney eb6c15caba Update iterator properly
This seems to fix #1266
2017-12-05 13:12:10 -05:00
Hayato Ikoma 39a7815f80 Fix the display of an grayscale image for image-nonsupported backends 2017-12-05 08:54:54 -08:00
Daniel SchwabenederandGitHub 4bbe367aab Merge pull request #1278 from JackDevine/master
Examples are limited to 90 columns.
2017-12-05 16:53:41 +01:00
Daniel SchwabenederandGitHub 7d50c7e4fe Merge pull request #1280 from daschw/default-magic
Default magic
2017-12-05 16:51:49 +01:00
JackDevine 5d0adb1783 Add comma 2017-12-05 08:36:04 +13:00
Daniel Schwabeneder 81ef4bdee8 remove _magic_arguments 2017-12-04 19:45:21 +01:00
Daniel Schwabeneder 2cf365d36d Allow magic arguments in default() 2017-12-04 19:34:02 +01:00
Jack DevineandGitHub eff8159d46 Merge branch 'master' into master 2017-12-04 22:44:31 +13:00
Jack DevineandGitHub f0e4f4dc9d Merge branch 'master' into master 2017-12-04 22:42:26 +13:00
JackDevine e02a70249e Examples are limited to 90 columns.
Thanks @daschw for pointing out the correct place to make these
changes. I have also changed the explanation texts, which may be a
little overkill, but I do think that the style guides apply to Markdown
string too (could be wrong though).
2017-12-04 22:34:45 +13:00
Daniel SchwabenederandGitHub 863ec08681 Merge pull request #1274 from daschw/pyplot-framestyle_grid
PyPlot: set tick marks color to match grid color for framestyle = :grid
2017-12-02 10:16:08 +01:00
Daniel Schwabeneder 28c958fb20 set tick marks color to grid color for framestyle = :grid 2017-12-01 16:14:59 +01:00
Daniel SchwabenederandGitHub 4c9f4a55d5 Merge pull request #1271 from daschw/gr-legend
allow to change the foreground_color_legend in gr
2017-11-30 16:50:18 +01:00
Daniel Schwabeneder a7fcf77251 allow to change the foreground_color_legend in gr 2017-11-30 16:26:48 +01:00
Daniel SchwabenederandGitHub a57745ed64 Merge pull request #1270 from daschw/grid
Extend grid lines to axes limits for GR (and GLVisualize)
2017-11-30 13:00:48 +01:00
Daniel Schwabeneder dd16c7d560 extend grid lines to axes limits 2017-11-30 11:47:20 +01:00
Daniel SchwabenederandGitHub 7f3780a20d Merge pull request #1269 from daschw/tests
use new StatPlots df syntax in testexamples
2017-11-30 11:16:10 +01:00
Daniel SchwabenederandGitHub 99c8713e7f Merge pull request #1268 from daschw/contour-fill
fix axes limits for fill=true in 3d plots (fix #1267)
2017-11-30 11:15:53 +01:00
Daniel Schwabeneder 49eb2c426d update testexample 30 2017-11-30 11:05:05 +01:00
Daniel Schwabeneder 4c55ff5df8 use new StatPlots df syntax in testexamples 2017-11-30 11:01:12 +01:00
Daniel Schwabeneder 714f8dea1d fix axes limits for fill=true in 3d plots 2017-11-30 09:45:09 +01:00
Josef HeinenandGitHub 1419a919aa Merge pull request #1260 from jheinen/master
gr: added support for non-string legend labels
2017-11-22 21:46:38 +01:00
Josef Heinen 6d4717fc96 gr: added support for non-string legend labels 2017-11-22 21:26:53 +01:00
Josef HeinenandGitHub 6a8f4caee3 Merge pull request #1258 from jheinen/master
gr: fix 'hidden window' problem after savefig
2017-11-21 14:58:12 +01:00
Josef Heinen dbf96a69d7 gr: fix 'hidden window' problem after savefig 2017-11-21 14:45:00 +01:00
Daniel SchwabenederandGitHub 0519f18bd7 Merge pull request #1257 from daschw/pyplot-fonts
fix guidefontamily typo in pyplot
2017-11-20 16:56:38 +01:00
Daniel Schwabeneder f7765c80b8 fix guidefontamily typo in pyplot 2017-11-20 16:54:05 +01:00
Daniel SchwabenederandGitHub f2e2ffa170 Merge pull request #1255 from daschw/fonts
Allow setting fonts in recipes (fix #555)
2017-11-20 15:17:33 +01:00
Daniel SchwabenederandGitHub b2a816452d Merge pull request #1242 from biggsbiggsby/patch-1
Generate a palette for each gif frame; Fixes #1239
2017-11-20 11:01:28 +01:00
Daniel SchwabenederandGitHub 299e9a85f2 Merge pull request #1253 from romainFr/pull-request/c01d8199
Plotly : always define range explicitely. Solves axis linking #1124
2017-11-20 08:40:12 +01:00
Daniel SchwabenederandGitHub ad34863bd6 Merge pull request #1254 from daschw/axes-limits
expand axes extrema for heatmap edges
2017-11-20 08:40:01 +01:00
Daniel Schwabeneder 129a91b36f update arg description 2017-11-19 21:18:04 +01:00
Daniel Schwabeneder 78f10de8cd update inspectdr 2017-11-19 20:44:22 +01:00
Daniel Schwabeneder 189b2e5cd6 update glvisualize 2017-11-19 20:36:26 +01:00
Daniel Schwabeneder d4f67ec3b5 update glvisualize 2017-11-19 20:31:28 +01:00
Daniel Schwabeneder 7ec54b9c2e update plotly(js) 2017-11-19 19:54:52 +01:00
Daniel Schwabeneder 60d20ea998 update pyplot 2017-11-19 18:15:22 +01:00
Daniel Schwabeneder e80a73cc1c fix magic font argument and cascading font defaults 2017-11-19 16:59:54 +01:00
Daniel Schwabeneder 6e51a08694 fix errors 2017-11-19 15:36:11 +01:00
Daniel Schwabeneder 0da6f6b4a4 update gr 2017-11-19 15:32:30 +01:00
Daniel Schwabeneder ba3e75e710 fix errors 2017-11-19 15:16:49 +01:00
Daniel Schwabeneder 8fee5e0de7 implement titlefont legendfont tickfont and guidefont functions to construct font objects from subplots and axes 2017-11-19 14:58:30 +01:00
Daniel Schwabeneder 68a060b7eb implement titlefont, legendfont, tickfont and guidefont magic keyword arguments 2017-11-19 14:31:30 +01:00
Daniel Schwabeneder 9f5be974b6 add fontfamily, fontsize, fonthalign, fontvalign, fontrotation, fontcolor keywords 2017-11-19 14:02:49 +01:00
Daniel Schwabeneder ea976d5f08 expand axes extrema for heatmap edges 2017-11-19 12:53:11 +01:00
Daniel SchwabenederandGitHub 892d68e792 Merge pull request #1251 from daschw/pyplot-legend
PyPlot: change legend symbols for shapes and filled plots
2017-11-18 08:43:23 +01:00
Romain FranconvilleandGitHub 5a0744e2f1 Remove commented code 2017-11-17 16:06:14 -05:00
Romain Franconville c01d8199f9 Also include scaling 2017-11-17 15:29:55 -05:00
Romain Franconville df023d6bdb Always define axis range explicitely 2017-11-17 15:02:16 -05:00
Daniel Schwabeneder 4bfb562477 remove extra space 2017-11-17 13:01:13 +01:00
Daniel Schwabeneder 4bc01b92bd avoid too big linewidths in legend 2017-11-17 12:59:20 +01:00
biggsbiggsbyandGitHub ee0f4e11ea Update animation.jl
Changed palette for each frame to an option, made the default palette a lossless bmp file for best quality/filesize, but still compatible with FFMPEG 3.4 on Win7 x64
2017-11-17 12:35:36 +01:00
Daniel Schwabeneder 1aa780f0a2 change legend symbols for shapes and filled plots on pyplot 2017-11-17 11:33:10 +01:00
biggsbiggsbyandGitHub cf58f3cbf2 Update animation.jl
Generates a color palette for each frame (instead of each animation) to improve quality, and avoid palette file format issues in FFMPEG 3.4
2017-11-17 10:30:23 +01:00
Michael Krabbe BorregaardandGitHub 18619e9010 Merge pull request #1246 from huckl3b3rry87/pull-request/ae37dce0
allow legend to be outside for pgfplots()
2017-11-14 20:33:20 +00:00
Huckleberry Febbo ae37dce0f3 allow legend to be outside for pgfplots() 2017-11-14 13:43:17 -05:00
Michael Krabbe BorregaardandGitHub e48831d092 Merge pull request #1243 from apalugniok/polar-output
Correct polar tick alignment for PGFPlots.
2017-11-14 15:05:15 +01:00
Andrew Palugniok 99f25ef744 Fix typo. 2017-11-14 13:49:53 +00:00
biggsbiggsbyandGitHub acf6e86c0f gif animation.jl
Change palette from png to gif to avoid png encoding bug in ffmpeg
2017-11-14 09:39:59 +01:00
Michael Krabbe BorregaardandGitHub 19192b622b Merge pull request #1224 from hessammehr/master
Fix for #1138
2017-11-13 17:06:03 +01:00
Michael Krabbe BorregaardandGitHub 183f399341 Merge pull request #1208 from apalugniok/polar-output
Polar plots consistency
2017-11-13 05:17:46 +01:00
Andrew Palugniok 240c1efab9 Improve default radial axis padding. 2017-11-12 18:09:08 +00:00
Andrew Palugniok 8bbdb0f1b8 Adds radial data filtering for points within axis limits. 2017-11-12 18:08:40 +00:00
Daniel SchwabenederandGitHub ecee135a63 Merge pull request #1230 from daschw/pgfplots-legend-symbols
change pgfplots legend symbol for shapes and filled plots (fix #1215)
2017-11-09 09:57:43 +01:00
Daniel Schwabeneder 51d4630405 change pgfplots legend symbol for shapes and filled plots 2017-11-08 22:02:40 +01:00
Michael Krabbe BorregaardandGitHub 60e7695546 Merge pull request #1228 from PallHaraldsson/patch-1
Typo?
2017-11-07 12:29:10 +01:00
Páll HaraldssonandGitHub 6d14a858a3 Typo?
Guessing here, 0.2.0 must be really old?
2017-11-07 11:11:46 +00:00
Andrew Palugniok 08a6f3af36 Allow custom radial ticks for GR. Fix polar ylims for non-zero ymin values in GR. 2017-11-05 10:37:51 +00:00
Andrew Palugniok cc43202e8f Fix radial axis tick alignment for GR. 2017-11-04 23:04:49 +00:00
Hessam Mehr 8fb3f3b1c9 Fixed for #1138 2017-11-04 15:20:41 -07:00
Andrew Palugniok 2fe2ff474c Implement grid attributes for polar plots. 2017-11-04 21:27:02 +00:00
Andrew Palugniok f0ad851aa7 Make radial axis vertical. 2017-11-03 19:45:17 +00:00
Daniel SchwabenederandGitHub ab29a712c0 Merge pull request #1221 from daschw/gr-contour-lw
allow setting the linewidth for contour plots in GR
2017-11-03 11:50:30 +01:00
Daniel Schwabeneder 8dd264c4da remove unnecessary line 2017-11-03 10:15:55 +01:00
Daniel Schwabeneder 40282ae23a allow setting the linestyle for contours on GR 2017-11-03 10:02:16 +01:00
Josef HeinenandGitHub ed75369c6d Merge pull request #1220 from jheinen/master
gr: use correct aspect ratio (fixes #1219)
2017-11-02 22:15:30 +01:00
Josef HeinenandGitHub b34f4141a2 Update gr.jl 2017-11-02 21:53:11 +01:00
Daniel Schwabeneder 5d5d8f073a allow setting the linewidth for contour plots in GR 2017-11-02 20:38:06 +01:00
Josef Heinen f690961af2 gr: use correct aspect ratio (fixes #1219) 2017-11-02 20:12:11 +01:00
Andrew Palugniok 12aa43ff5f Fix deprecations. 2017-11-02 16:33:05 +00:00
Andrew Palugniok 4f171e3eb5 Add handling of polar axes. 2017-11-02 16:32:57 +00:00
Daniel SchwabenederandGitHub 671f5c3a68 Merge pull request #1213 from daschw/fillrange
Make `fill = true` fill to zero
2017-10-31 09:21:47 +01:00
Daniel SchwabenederandGitHub 1f12185441 Merge pull request #1214 from apalugniok/plotly-colorbar
Fix colorbar always displaying in Plotly. (Fixes #1211)
2017-10-31 09:21:31 +01:00
Andrew Palugniok a3e599e38d Fix colorbar always displaying in Plotly. 2017-10-30 19:50:02 +00:00
Daniel Schwabeneder 5a3779e431 fill = true fills to 0 2017-10-30 10:49:22 +01:00
Michael Krabbe BorregaardandGitHub 5ddcdef1b4 Merge pull request #1210 from mkborregaard/master
add hline marker to pgfplots
2017-10-27 19:22:11 +02:00
Michael K. Borregaard 7b6b44b284 add hline to pgfplots 2017-10-27 15:52:32 +02:00
Michael Krabbe BorregaardandGitHub a691d5c7e8 Merge pull request #1187 from anowacki/movie-compatibility
Animations: improve movie compatibility when using ffmpeg
2017-10-25 11:44:03 +02:00
Josef HeinenandGitHub 7cf40b16df Merge pull request #1206 from jheinen/master
gr: implement title location
2017-10-24 20:06:00 +02:00
Josef Heinen ad6b707abf gr: implement title location 2017-10-24 19:50:18 +02:00
Andy Nowacki 133052b58c Animations: improve movie compatibility when using ffmpeg
Add the -pix_fmt yuv420p option when using ffmpeg to save
animations with the mov or mp4 commands. This improves
compatibility of the movie files since many players do not
support the ffmpeg defaults.

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

See the following for more information:
- https://trac.ffmpeg.org/wiki/Encode/H.264 ('Compatibility')
- https://apple.stackexchange.com/questions/166553/why-wont-video-from-ffmpeg-show-in-quicktime-imovie-or-quick-preview
2017-10-23 14:16:12 +01:00
Michael Krabbe BorregaardandGitHub 226bf7e705 Merge pull request #1199 from mkborregaard/make-revise-possible
Make revise possible
2017-10-21 07:40:53 +02:00
Michael K. Borregaard cdcbdc308c include backend files 2017-10-20 22:45:04 +02:00
Daniel SchwabenederandGitHub 5bfa6151ac Merge pull request #1195 from apalugniok/pgfplots-logticks
Fix log scale ticks LaTeX error for PGFPlots. (fixes #1192)
2017-10-19 17:38:44 +02:00
Daniel SchwabenederandGitHub 020760f0c8 Merge pull request #1190 from daschw/tests
Minor test_example changes (close #1162)
2017-10-19 17:38:25 +02:00
Andrew Palugniok 0c4750547a Fix LaTeX error for log scale ticks. 2017-10-19 15:30:45 +01:00
Michael Krabbe BorregaardandGitHub 9c46509f84 Merge pull request #1185 from H-M-H/animation_fix
Use ffmpeg & palette to create gifs, closes #1050
2017-10-18 22:28:56 +02:00
Daniel SchwabenederandGitHub 928a2d646b Merge pull request #1189 from daschw/spy
use fg_color for matrices with unique non-zeros in spy recipe
2017-10-18 21:31:54 +02:00
Daniel Schwabeneder 7ffd1fc9c2 some further improvements for framestyle and group testexamples 2017-10-18 21:24:28 +02:00
Daniel Schwabeneder 6d4f456826 fix framestyle testexample 2017-10-18 21:06:37 +02:00
Daniel Schwabeneder e78bf87377 update some test_examples 2017-10-18 20:51:43 +02:00
Daniel Schwabeneder c76fc5b909 use fg_color for matrices with unique non-zeros in spy recipe 2017-10-18 20:47:06 +02:00
Michael Krabbe BorregaardandGitHub eecd14f53a Merge pull request #1036 from JuliaPlots/fbot/deps
Fix deprecations
2017-10-17 21:45:13 +02:00
femtocleaner[bot] ef29b4a5b0 Fix deprecations 2017-10-17 09:59:09 +00:00
Daniel SchwabenederandGitHub d6748792e9 Merge pull request #1184 from daschw/gr-box-flip
fix combination of box framestyle and flip on gr
2017-10-17 09:23:47 +02:00
Daniel SchwabenederandGitHub ae9c26504d Merge pull request #1183 from daschw/spy
spy recipe: change default color for matrices with unique values
2017-10-17 09:23:25 +02:00
HMH 7f7b543e18 Use ffmpeg & palette to create gifs, closes #1050
First let ffmpeg generate a colorpalette so it uses the limited amount
of colors available properly and only then create the actual gif using
the generated palette. This replaces convert completely as it yields far
worse results for long gifs and is considerably slower.
2017-10-16 23:53:00 +02:00
Daniel Schwabeneder 2464d7bd9a fix combination of box framestyle and flip on gr 2017-10-16 21:46:23 +02:00
Daniel Schwabeneder 3ce71999e2 spy recipe: change default color for matrices with unique values 2017-10-16 21:24:13 +02:00
Daniel SchwabenederandGitHub 7f9d83c088 Merge pull request #1168 from darwindarak/dd/reset-defaults
RFC: Add (back?) ability to reset defaults
2017-10-16 20:17:02 +02:00
Daniel SchwabenederandGitHub e8f6e7b56c Merge pull request #1181 from daschw/colorbar
Fix GR annotations with colorbar (fix #1179)
2017-10-16 19:19:03 +02:00
Daniel Schwabeneder 94c0957e11 draw colorbar in the end 2017-10-16 18:04:46 +02:00
Michael Krabbe BorregaardandGitHub b0ffe03c99 Merge pull request #1178 from JuliaPlots/patch-appveyor-readme
Fix appveyor badge
2017-10-15 13:01:03 +02:00
Michael Krabbe BorregaardandGitHub 8ea878a2a2 Fix appveyor badge 2017-10-15 12:43:15 +02:00
Michael Krabbe BorregaardandGitHub bbbab914d8 Merge pull request #1177 from JuliaPlots/revert-1176-no_copy
Revert "Don't copy input arguments - fix #1175"
2017-10-14 22:56:12 +02:00
Michael Krabbe BorregaardandGitHub 735a45b4e9 Revert "Don't copy input arguments - fix #1175" 2017-10-14 22:55:23 +02:00
Michael Krabbe BorregaardandGitHub a4558302f2 Merge pull request #1176 from mkborregaard/no_copy
Don't copy input arguments - fix #1175
2017-10-14 22:39:00 +02:00
Michael K. Borregaard d8ba26f790 Don't copy input arguments into d 2017-10-14 08:52:51 +02:00
Michael Krabbe BorregaardandGitHub dcc3055dec Merge pull request #1174 from mkborregaard/fix_hist_weights
fix `weights` in `histogram`; closes #1173
2017-10-13 17:09:06 +02:00
Michael K. Borregaard 6db7116db9 add weights argument to histogram example 2017-10-13 17:08:26 +02:00
Michael K. Borregaard 422988b3f6 fix weights in histogram 2017-10-13 12:38:56 +02:00
Michael Krabbe BorregaardandGitHub 2f04c5fec8 Merge pull request #1141 from apalugniok/apalugniok-test2
Adds camera attribute for 3D plots.
2017-10-13 00:26:39 +02:00
Pietro VertechiandGitHub e811aa44b0 Merge pull request #1164 from piever/svg
fix #750 : save svg plotlyjs
2017-10-12 14:09:41 +01:00
Darwin Darakananda 4c7ab232d5 Add (back?) ability to reset defaults 2017-10-11 10:25:54 -07:00
Daniel SchwabenederandGitHub fc42641469 Merge pull request #1163 from daschw/gr-flip
fix flip for GR
2017-10-11 14:53:40 +02:00
Michael Krabbe BorregaardandGitHub b71cfce105 Merge pull request #1155 from mkborregaard/newspy
RFC: New spy implementation
2017-10-11 09:01:58 +02:00
Pietro Vertechi be55c1ad6f save svg plotlyjs 2017-10-10 23:29:18 +01:00
Daniel Schwabeneder 979a846298 fix flip for GR 2017-10-10 23:26:39 +02:00
Daniel SchwabenederandGitHub a4c59ce964 Merge pull request #1153 from daschw/gr-marker_z
Fix marker_z for 3D plots on GR (test example 24) (fix #1152)
2017-10-10 21:06:01 +02:00
Daniel SchwabenederandGitHub 208c70f933 Merge pull request #1161 from daschw/tests
update version for tests
2017-10-10 19:51:47 +02:00
Daniel Schwabeneder 9dcbc06b3d update version for tests 2017-10-10 19:50:45 +02:00
Josef HeinenandGitHub e3f6da382d Merge pull request #1158 from jheinen/master
gr: fixed colorbar problem for flipped axes
2017-10-10 12:20:49 +02:00
Josef Heinen cc201ce4e7 gr: fixed colorbar problem for flipped axes 2017-10-10 10:54:29 +02:00
Michael K. Borregaard 08bdd11410 New spy implementation 2017-10-09 21:19:32 +02:00
Daniel Schwabeneder bac192d825 remove unnecessary lines 2017-10-09 17:20:36 +02:00
Daniel Schwabeneder 55c968f138 fix marker_z for 3D plots - draw colorbar once per series 2017-10-09 17:13:44 +02:00
Andrew Palugniok 6df2bc2790 Clarify gr.jl setspace() rounding syntax. 2017-10-09 11:40:04 +01:00
Andrew Palugniok f8576c7135 Remove :view alias for :camera attribute. 2017-10-09 11:33:24 +01:00
Daniel SchwabenederandGitHub 7d220f571d Merge pull request #1142 from daschw/line_z
Fix linestyle on GR (fix #1139)(fix #1123)
2017-10-08 13:50:43 +02:00
Christopher RackauckasandGitHub eda1ebe36b Fix docs link
Ugh, flubbed that one. There's the `http://`
2017-10-07 13:24:03 -07:00
Christopher RackauckasandGitHub ae4288719f Merge pull request #1145 from JuliaPlots/ChrisRackauckas-patch-3
New docs page link
2017-10-07 13:22:53 -07:00
Christopher RackauckasandGitHub a016b655f4 New docs page link 2017-10-07 13:06:08 -07:00
Andrew Palugniok f4bc2e0649 Convert :camera attribute input for GR. 2017-10-07 20:05:53 +01:00
Andrew Palugniok cf6f7035b6 Added extra :camera aliases. 2017-10-07 20:05:05 +01:00
Daniel Schwabeneder cb7498a30d fix linestyle on gr 2017-10-07 21:02:14 +02:00
Andrew Palugniok ccb3cadd2a Implemented camera attribute for Plotly/PlotlyJS. 2017-10-06 20:47:04 +01:00
Andrew Palugniok 0fb1a0ed6b Implemented camera attribute for PGFPlots. 2017-10-06 20:47:04 +01:00
Andrew Palugniok 94e79f1e4c Implemented camera attribute for PyPlot. 2017-10-06 20:46:25 +01:00
Andrew Palugniok 65a28e76e5 Implemented camera attribute for GR. 2017-10-06 20:46:25 +01:00
Andrew Palugniok 0c5a9172ab Added camera attribute processing. 2017-10-06 20:46:25 +01:00
Daniel SchwabenederandGitHub 1c21a0d609 Merge pull request #1132 from darwindarak/dd/pyplot-linez
RFC: Fix `line_z` for PyPlot backend (fix #1021)
2017-10-06 09:24:57 +02:00
Darwin Darakananda 16d18552f8 Allow line_z to specify color across multiple lines 2017-10-05 20:49:17 -07:00
Daniel SchwabenederandGitHub 001cb80cfe Merge pull request #1120 from daschw/axis-false
showaxis attribute
2017-10-05 23:17:55 +02:00
Daniel SchwabenederandGitHub bd14d9c07b Merge pull request #1108 from AnkurD/colorbar
Colorbar takes font style from Y Axis
2017-10-05 13:58:41 +02:00
Michael Krabbe BorregaardandGitHub 08bbde327f Merge pull request #1135 from mkborregaard/drop-travis-pyplot
Drop tests for pyplot (temporarily)
2017-10-05 13:42:45 +02:00
Michael K. Borregaard 12488bf2b0 Drop tests for pyplot (temporarily)
revisit 12 oct
2017-10-05 13:24:21 +02:00
Michael Krabbe BorregaardandGitHub 4bf0d69f79 Merge pull request #1133 from JackDevine/legend-markers
PyPlot legends now show marker types.
2017-10-05 12:58:02 +02:00
Michael K. Borregaard 78e3b69cc5 prec 2017-10-05 12:30:29 +02:00
Michael K. Borregaard 531a38bc39 no prec 2017-10-05 12:28:52 +02:00
Michael K. Borregaard 77fa5454e2 remember backticks 2017-10-05 12:27:51 +02:00
Michael Krabbe BorregaardandGitHub 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 BorregaardandGitHub af23074820 Merge pull request #1134 from mkborregaard/patch-release
ready for release
2017-10-05 12:22:52 +02:00
Michael K. Borregaard fdf2d5b20b ready for release 2017-10-05 12:22:12 +02:00
Michael K. Borregaard b37f2141a1 Also import px and pct into PlotMeasures
Necessary for example 29 to work
2017-10-05 12:12:54 +02:00
JackDevine 520dc80eeb Added marker strokes 2017-10-05 22:58:18 +13:00
JackDevine 878fa48afa PyPlot legends now show marker types. 2017-10-05 21:35:38 +13:00
Darwin Darakananda 514cd1bd37 normalize colors even when plotting without colorbars 2017-10-04 15:10:36 -07:00
Darwin Darakananda f5ee5ea814 Fix line_z for PyPlot backend
`LineCollection` expects an array with pairs of coordinates,
corresponding to the starting and ending points of each segment.
2017-10-04 14:26:35 -07:00
Daniel Schwabeneder e3b0f7cd94 pgfplots: remove axis arrows and implement origin and zerolines framestyles 2017-10-04 13:40:56 +02:00
Michael K. Borregaard 5567038cec simplify 2017-10-04 11:47:20 +02:00
Michael K. Borregaard 0327c9101e slight refactor for clarity 2017-10-04 11:44:20 +02:00
Michael K. Borregaard 3d86d5f530 Apply automatic limits for vectors of functions 2017-10-04 11:38:32 +02:00
Michael K. Borregaard 073724a84c reactivate 2017-10-03 15:14:10 +02:00
Michael Krabbe BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub a80c7ada27 Merge pull request #1116 from jw3126/replaceD
replace d by plotattributes inside recipes
2017-10-02 14:46:11 +02:00
Michael Krabbe BorregaardandGitHub 9bc6d0c7d1 Merge pull request #1122 from mkborregaard/bar_width_fix
Fix barwidth to minimum(diff) not mean(diff)
2017-10-02 11:16:25 +02:00
Michael K. Borregaard f3566a4933 sort before taking diff 2017-10-02 10:02:39 +02:00
Michael K. Borregaard cd958a6c68 Fix barwidth to minimum(diff) not mean(diff) 2017-10-02 08:53:41 +02:00
Michael K. Borregaard 4f6a920f72 Import Measures into Plots 2017-10-02 08:28:25 +02:00
Michael K. Borregaard b717cf1dc0 Rename submodule to PlotMeasures 2017-10-02 08:24:59 +02:00
Michael K. Borregaard 33e5a51a28 add submodule Measure 2017-10-02 07:59:04 +02:00
Daniel Schwabeneder ff751ca423 implement showaxis and basic framestyles for pgfplots 2017-10-01 20:29:46 +02:00
Daniel Schwabeneder 93df7f4367 implement showaxis for glvisualize 2017-10-01 19:09:24 +02:00
Josef HeinenandGitHub dca5a7ce4d Merge pull request #1119 from apalugniok/master
Change GR default 3D view angles
2017-10-01 12:50:51 +02:00
apalugniok bf4dd78a7d Change GR default 3D view angles to match PyPlot 2017-10-01 10:29:44 +01:00
Jan Weidner 489e484117 bump required RecipesBase to 0.2.3 2017-09-29 23:24:58 +02:00
Jan Weidner 6e1cc8449b replace d by plotattributes inside recipes 2017-09-29 23:09:34 +02:00
Daniel Schwabeneder 148ad8032f implement showaxis for pyplot 2017-09-29 20:16:27 +02:00
Daniel Schwabeneder 6d53594850 implement showaxis for plotly 2017-09-29 15:09:28 +02:00
Daniel Schwabeneder ee7a3b3686 general axis fixes and improvemennts 2017-09-29 13:41:54 +02:00
Daniel Schwabeneder 18188516ec implement showaxis attribute for gr 2017-09-29 11:48:17 +02:00
Michael Krabbe BorregaardandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 SchwabenederandGitHub fba1c66499 Merge pull request #1110 from daschw/line_z
RFC: Implement line_z and fill_z for GR
2017-09-28 00:12:12 +02:00
Daniel Schwabeneder 1c04823877 reset tick size for gr and glvisualize 2017-09-28 00:07:58 +02:00
Daniel Schwabeneder 6c84624d71 fix pgfplots 2017-09-27 23:22:55 +02:00
Daniel Schwabeneder 69fa9e7b10 implement tick_direction for PGFPlots 2017-09-27 17:07:09 +02:00
Daniel Schwabeneder 350237a774 add tick_direction to supported arguments 2017-09-27 13:56:12 +02:00
Daniel Schwabeneder b73ea55bbd implement tick_direction for GR, PyPlot, Plotly and GLVisualize 2017-09-27 13:53:06 +02:00
Daniel Schwabeneder 9eac6a1db0 fix fillalpha 2017-09-26 17:40:54 +02:00
Daniel Schwabeneder ea6ab46a13 fix fill_z for shapes (draw colorbar once) 2017-09-26 17:18:35 +02:00
Daniel Schwabeneder 5f84865365 implement fill_z and line_z for GR 2017-09-26 16:58:46 +02:00
AnkurD 5b3c41bd77 Colorbar takes font style from Y Axis 2017-09-26 17:22:17 +09:00
AnkurD c6b7ff6c75 Colorbar takes font style from Y Axis 2017-09-26 17:16:03 +09:00
Daniel Schwabeneder 337a107168 different colors for different line segments in GR 2017-09-25 17:22:13 +02:00
Daniel SchwabenederandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 SchwabenederandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 SchwabenederandGitHub af9d97d561 Merge pull request #1077 from daschw/seriestype-error
improve recipe error
2017-09-07 13:29:09 +02:00
Daniel SchwabenederandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 VertechiandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 82877dc53e Merge pull request #1009 from JackDevine/add-stride
Add stride to wireframe/surface
2017-09-03 07:35:35 +02:00
Jack DevineandGitHub 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 HeinenandGitHub 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 BorregaardandGitHub 73a2839e34 Merge pull request #1037 from mkborregaard/hist-description
changes default histogram bins
2017-09-01 13:20:12 +02:00
Michael Krabbe BorregaardandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 HeinenandGitHub 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 SchwabenederandGitHub 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
pieverandGitHub ca5310025f Merge pull request #1033 from piever/group
Group now groups kw arguments as well
2017-08-29 17:16:40 +01:00
pieverandGitHub 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 BorregaardandGitHub 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
pieverandGitHub 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 SchwabenederandGitHub be04828d35 Merge pull request #1042 from daschw/ds-blackborder
make linecolor default to :auto
2017-08-26 15:58:11 +02:00
Josef HeinenandGitHub 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 BorregaardandGitHub 95a6d24111 Merge pull request #990 from jverzani/patch-1
Update appveyor.yml
2017-08-25 08:51:30 +02:00
Michael Krabbe BorregaardandGitHub 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 HeinenandGitHub 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 BorregaardandGitHub 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 SchwabenederandGitHub 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 HeinenandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 RackauckasandGitHub 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 SchwabenederandGitHub 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 BorregaardandGitHub 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 BorregaardandGitHub 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 SchwabenederandGitHub e61d435b00 Merge pull request #1020 from daschw/ds-precompile
reactivate precompilation
2017-08-18 00:58:55 +02:00
Daniel Schwabeneder 4c1c092234 reactivate precompilation 2017-08-18 00:46:02 +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
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
john verzaniandGitHub 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 verzaniandGitHub 8c3c07acb7 Update appveyor.yml
remove v0.5 testing from appveyor
2017-07-27 16:56:17 -04:00
john verzaniandGitHub 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
42 changed files with 2144 additions and 881 deletions
+84 -3
View File
@@ -3,14 +3,95 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.12!
- All new development should target 0.14!
- 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.14.0
- remove use of imagemagick; saving gifs now requires ffmpeg
- improvements to ffmpeg gif quality and speed
- overhaul of fonts, allows setting fonts in recipes and with magic arguments
- added `camera` attribute to control camera position for 3d plots
- added `showaxis` attribute to control which axes to display
- improvements of polar plots axes, and better backend consistency
- changed the 'spy' recipe back to using heatmap
- added `scatterpath` seriestype
- allow plotlyjs to save svg
- add `reset_defaults()` function to reset plot defaults
- update syntax to 0.6
- make `fill = true` fill to 0 rather than to 1
- use new `@df` syntax in StatPlots examples
- allow changing the color of legend box
- implement `title_location` for gr
- add `hline` marker to pgfplots - fixes errorbars
- pyplot legends now show marker types
- pyplot colorbars take font style from y axis
- pyplot tickmarks color the same as axis color
- allow setting linewidth for contour in gr
- allow legend to be outside plot area for pgfplots
- expand axis extrema for heatmap
- extendg grid lines to axis limits
- fix `line_z` for pyplot and gr
- fixed colorbar problem for flipped axes with gr
- fix marker_z for 3d plots in gr
- fix `weights` functionality for histograms
- fix gr annotations with colorbar
- fix aspect ratio in gr
- fix "hidden window" problem after savefig in gr
- fix pgfplots logscale ticks error
- fix pgfplots legends symbols
- fix axis linking for plotlyjs
- fix plotting of grayscale images
## 0.13.1
- fix a bug when passing a vector of functions with no bounds (e.g. `plot([sin, cos])`)
- export `pct` and `px` from Plots.PlotMeasures
## 0.13.0
- support `plotattributes` rather than `d` in recipes
- no longer export `w`, `h` and names from Measures.jl; use `using Plots.PlotMeasures` to get these names back
- `bar_width` now depends on the minimum distance between bars, not the mean
- better automatic x axis limits for plotting Functions
- `tick_direction` attribute now allows ticks to be on the inside of the plot border
- removed a bug where `p1 = plot(randn(10)); plot(p1, p2)` made `display(p1)` impossible
- allow `plot([])` to generate an empty plot
- add `origin` framestyle
- ensure finite bin number on histograms with only one unique value
- better automatic histogram bins for 2d histograms
- more informative error message on passing unsupported seriestype in a recipe
- allow grouping in user recipes
- GR now has `line_z` and `fill_z` attributes for determining the color of shapes and lines
- change GR default view angle for 3D plots to match that of PyPlot
- fix `clims` on GR
- fix `marker_z` for plotly backend
- implement `framestyle` for plotly
- fix logscale bug error for values < 1e-16 on pyplot
- fix an issue on pyplot where >1 colorbar would be shown if there was >1 series
- fix `writemime` for eps
## 0.12.4
- added a new `framestyle` argument with choices: :box, :semi, :axes, :grid and :none
- changed the default bar width to 0.8
- added working ribbon to plotly backend
- ensure that automatic ticks always generate 4 to 8 ticks
- group now groups keyword arguments of the same length as the input
- allow passing DateTime objects as ticks
- allow specifying the number of ticks as an integre
- fix bug on errorbars in gr
- fixed some but not all world age issues
- better margin with room for text
- added a `match` option for linecolor
- better error message un unsupported series types
- add a 'stride' keyword for the pyplot backend
## 0.12.3
- new grid line style defaults
@@ -61,7 +142,7 @@
#### 0.11.0
- julia 0.6 compatibility
- matplotlib 0.2.0 compatibility
- matplotlib 2.0 compatibility
- add inspectdr backend
- improved histogram functionality:
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)
+5 -2
View File
@@ -1,13 +1,16 @@
# Plots
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/mkborregaard/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
<!-- [![Coverage Status](https://coveralls.io/repos/tbreloff/Plots.jl/badge.svg?branch=master)](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
<!-- [![codecov.io](http://codecov.io/github/tbreloff/Plots.jl/coverage.svg?branch=master)](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
#### Author: Thomas Breloff (@tbreloff)
#### Created by Tom Breloff (@tbreloff)
#### Maintained by the [JuliaPlot members](https://github.com/orgs/JuliaPlots/people)
Plots is a plotting API and toolset. My goals with the package are:
@@ -19,4 +22,4 @@ Plots is a plotting API and toolset. My goals with the package are:
- **Lightweight**. Very few dependencies.
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
View the [full documentation](http://juliaplots.github.io).
View the [full documentation](http://docs.juliaplots.org/latest).
+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"
+67 -26
View File
@@ -15,6 +15,8 @@ using Base.Meta
import Showoff
import StatsBase
using Requires
export
grid,
bbox,
@@ -110,13 +112,13 @@ export
# ---------------------------------------------------------
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
ignorenan_minimum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.minimum(x)
ignorenan_minimum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.minimum(x)
ignorenan_minimum(x) = Base.minimum(x)
ignorenan_maximum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.maximum(x)
ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
ignorenan_maximum(x) = Base.maximum(x)
ignorenan_mean{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.mean(x)
ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
ignorenan_mean(x) = Base.mean(x)
ignorenan_extrema{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.extrema(x)
ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
ignorenan_extrema(x) = Base.extrema(x)
# ---------------------------------------------------------
@@ -133,11 +135,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")
@@ -188,32 +199,62 @@ 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...)
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
"Set xticks for an existing plot"
xticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
@@ -222,22 +263,22 @@ let PlotOrSubplot = Union{Plot, Subplot}
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...)
xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
yticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
xticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
xticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
yticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
+29 -32
View File
@@ -1,5 +1,5 @@
immutable Animation
"Represents an animation object"
struct Animation
dir::String
frames::Vector{String}
end
@@ -9,7 +9,12 @@ function Animation()
Animation(tmpdir, String[])
end
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
"""
frame(animation[, plot])
Add a plot (the current plot if not specified) to an existing animation
"""
function frame(anim::Animation, plt::P=current()) where P<:AbstractPlot
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename))
@@ -20,7 +25,7 @@ giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
type FrameIterator
mutable struct FrameIterator
itr
every::Int
kw
@@ -49,44 +54,36 @@ end
# -----------------------------------------------
"Wraps the location of an animated gif so that it can be displayed"
immutable AnimatedGif
struct AnimatedGif
filename::String
end
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...)
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn; kw...)
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
const _imagemagick_initialized = Ref(false)
function buildanimation(animdir::AbstractString, fn::AbstractString;
fps::Integer = 20, loop::Integer = 0)
function buildanimation(animdir::AbstractString, fn::AbstractString,
is_animated_gif::Bool=true;
fps::Integer = 20, loop::Integer = 0,
variable_palette::Bool=false)
fn = abspath(fn)
try
if !_imagemagick_initialized[]
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
include(file)
end
_imagemagick_initialized[] = true
if is_animated_gif
if variable_palette
# generate a colorpalette for each frame for highest quality, but larger filesize
palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`)
else
# generate a colorpalette first so ffmpeg does not have to guess it
run(`ffmpeg -v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
# then apply the palette to get better results
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`)
end
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
# high quality
speed = round(Int, 100 / fps)
run(`convert -delay $speed -loop $loop $(joinpath(animdir, "*.png")) -alpha off $fn`)
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
You may also need to install the imagemagick c++ library through your operating system.
Will try ffmpeg, but it's lower quality...)""")
# low quality
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -y $fn`)
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
else
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
end
info("Saved animation to ", fn)
+32 -7
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`.",
@@ -66,11 +66,17 @@ const _arg_desc = KW(
:dpi => "Number. Dots Per Inch of output figures",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
# subplot args
:title => "String. Subplot title.",
:title_location => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefont => "Font. Font of subplot title.",
:titlefontfamily => "String or Symbol. Font family of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center",
:titlefontrotation => "Real. Font rotation of subplot title",
:titlefontcolor => "Color Type. Font color of subplot title",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
@@ -79,7 +85,12 @@ const _arg_desc = KW(
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
:legendtitle => "String or nothing (default). Sets the legend title.",
:legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.",
@@ -93,6 +104,8 @@ const _arg_desc = KW(
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args
:guide => "String. Axis guide (label).",
@@ -102,16 +115,28 @@ const _arg_desc = KW(
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
:tickfont => "Font. Font of axis tick labels.",
:guidefont => "Font. Font of axis guide (label).",
:tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center",
:tickfontrotation => "Real. Font rotation of tick labels",
:tickfontcolor => "Color Type. Font color of tick labels",
:guidefontfamily => "String or Symbol. Font family of axes guides.",
:guidefontsize => "Integer. Font pointsize of axes guides.",
:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center",
:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center",
:guidefontrotation => "Real. Font rotation of axes guides",
:guidefontcolor => "Color Type. Font color of axes guides",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`"
)
+198 -34
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)
@@ -166,8 +170,8 @@ const _scaleAliases = Dict{Symbol,Symbol}(
const _allGridSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on,
:none, :off,]
:all, :both, :on, :yes, :show,
:none, :off, :no, :hide]
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
hasgrid(arg::Void, letter) = false
hasgrid(arg::Bool, letter) = arg
@@ -175,12 +179,40 @@ 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; $letter\grid was set to `true` instead.")
warn("Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead.")
true
end
end
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allShowaxisSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on, :yes, :show,
:off, :no, :hide]
const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)]
showaxis(arg::Void, letter) = false
showaxis(arg::Bool, letter) = arg
function showaxis(arg::Symbol, letter)
if arg in _allGridSyms
arg in (:all, :both, :on, :yes) || contains(string(arg), string(letter))
else
warn("Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead.")
true
end
end
showaxis(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
const _framestyleAliases = Dict{Symbol, Symbol}(
:frame => :box,
:border => :box,
:on => :box,
:transparent => :semi,
:semitransparent => :semi,
)
const _bar_width = 0.8
# -----------------------------------------------------------------------------
const _series_defaults = KW(
@@ -190,7 +222,7 @@ const _series_defaults = KW(
:seriestype => :path,
:linestyle => :solid,
:linewidth => :auto,
:linecolor => :match,
:linecolor => :auto,
:linealpha => nothing,
:fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match,
@@ -232,6 +264,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.
)
@@ -240,6 +273,7 @@ const _plot_defaults = KW(
:background_color => colorant"white", # default for all backgrounds,
:background_color_outside => :match, # background outside grid,
:foreground_color => :auto, # default for all foregrounds, and title color,
:fontfamily => "sans-serif",
:size => (600,400),
:pos => (0,0),
:window_title => "Plots.jl",
@@ -259,7 +293,13 @@ const _plot_defaults = KW(
const _subplot_defaults = KW(
:title => "",
:title_location => :center, # also :left or :right
:titlefont => font(14),
:fontfamily_subplot => :match,
:titlefontfamily => :match,
:titlefontsize => 14,
:titlefonthalign => :hcenter,
:titlefontvalign => :vcenter,
:titlefontrotation => 0.0,
:titlefontcolor => :match,
:background_color_subplot => :match, # default for other bg colors... match takes plot default
:background_color_legend => :match, # background of legend
:background_color_inside => :match, # background inside grid
@@ -271,7 +311,12 @@ const _subplot_defaults = KW(
:legendtitle => nothing,
:colorbar => :legend,
:clims => :auto,
:legendfont => font(8),
:legendfontfamily => :match,
:legendfontsize => 8,
:legendfonthalign => :hcenter,
:legendfontvalign => :vcenter,
:legendfontrotation => 0.0,
:legendfontcolor => :match,
:annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal
@@ -282,6 +327,8 @@ const _subplot_defaults = KW(
:bottom_margin => :match,
:subplot_index => -1,
:colorbar_title => "",
:framestyle => :axes,
:camera => (30,30),
)
const _axis_defaults = KW(
@@ -292,8 +339,18 @@ const _axis_defaults = KW(
:rotation => 0,
:flip => false,
:link => [],
:tickfont => font(8),
:guidefont => font(11),
:tickfontfamily => :match,
:tickfontsize => 8,
:tickfonthalign => :hcenter,
:tickfontvalign => :vcenter,
:tickfontrotation => 0.0,
:tickfontcolor => :match,
:guidefontfamily => :match,
:guidefontsize => 11,
:guidefonthalign => :hcenter,
:guidefontvalign => :vcenter,
:guidefontrotation => 0.0,
:guidefontcolor => :match,
:foreground_color_axis => :match, # axis border/tick colors,
:foreground_color_border => :match, # plot area border/spines,
:foreground_color_text => :match, # tick text color,
@@ -306,6 +363,8 @@ const _axis_defaults = KW(
:gridalpha => 0.1,
:gridstyle => :solid,
:gridlinewidth => 0.5,
:tick_direction => :in,
:showaxis => true,
)
const _suppress_warnings = Set{Symbol}([
@@ -357,11 +416,13 @@ const _all_defaults = KW[
_axis_defaults_byletter
]
const _initial_defaults = deepcopy(_all_defaults)
# to be able to reset font sizes to initial values
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefont].pointsize,
:legendfont => _subplot_defaults[:legendfont].pointsize,
:tickfont => _axis_defaults[:tickfont].pointsize,
:guidefont => _axis_defaults[:guidefont].pointsize)
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefontsize],
:legendfont => _subplot_defaults[:legendfontsize],
:tickfont => _axis_defaults[:tickfontsize],
:guidefont => _axis_defaults[:guidefontsize])
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
@@ -423,7 +484,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,
@@ -491,9 +552,12 @@ 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_aliases(:camera, :cam, :viewangle, :view_angle)
# add all pluralized forms to the _keyAliases dict
for arg in keys(_series_defaults)
@@ -512,7 +576,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
@@ -542,6 +605,8 @@ function default(k::Symbol, v)
end
function default(; kw...)
kw = KW(kw)
preprocessArgs!(kw)
for (k,v) in kw
default(k, v)
end
@@ -551,6 +616,7 @@ function default(d::KW, k::Symbol)
get(d, k, default(k))
end
reset_defaults() = foreach(merge!, _all_defaults, _initial_defaults)
# -----------------------------------------------------------------------------
@@ -653,6 +719,9 @@ function processFillArg(d::KW, arg)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
elseif typeof(arg) <: Bool
d[:fillrange] = arg ? 0 : nothing
# fillrange function
elseif allFunctions(arg)
d[:fillrange] = arg
@@ -692,12 +761,44 @@ function processGridArg!(d::KW, arg, letter)
d[Symbol(letter, :gridlinewidth)] = arg
# color
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
warn("Skipped grid arg $arg.")
end
end
function processFontArg!(d::KW, fontname::Symbol, arg)
T = typeof(arg)
if T <: Font
d[Symbol(fontname, :family)] = arg.family
d[Symbol(fontname, :size)] = arg.pointsize
d[Symbol(fontname, :halign)] = arg.halign
d[Symbol(fontname, :valign)] = arg.valign
d[Symbol(fontname, :rotation)] = arg.rotation
d[Symbol(fontname, :color)] = arg.color
elseif arg == :center
d[Symbol(fontname, :halign)] = :hcenter
d[Symbol(fontname, :valign)] = :vcenter
elseif arg in (:hcenter, :left, :right)
d[Symbol(fontname, :halign)] = arg
elseif arg in (:vcenter, :top, :bottom)
d[Symbol(fontname, :valign)] = arg
elseif T <: Colorant
d[Symbol(fontname, :color)] = arg
elseif T <: Symbol || T <: AbstractString
try
d[Symbol(fontname, :color)] = parse(Colorant, string(arg))
catch
d[Symbol(fontname, :family)] = string(arg)
end
elseif typeof(arg) <: Integer
d[Symbol(fontname, :size)] = arg
elseif typeof(arg) <: Real
d[Symbol(fontname, :rotation)] = convert(Float64, arg)
else
warn("Skipped font arg: $arg ($(typeof(arg)))")
end
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
@@ -717,12 +818,13 @@ function preprocessArgs!(d::KW)
replaceAliases!(d, _keyAliases)
# clear all axis stuff
if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
d[:ticks] = nothing
d[:foreground_color_border] = RGBA(0,0,0,0)
d[:grid] = false
delete!(d, :axis)
end
# if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
# d[:ticks] = nothing
# d[:foreground_color_border] = RGBA(0,0,0,0)
# d[:foreground_color_axis] = RGBA(0,0,0,0)
# d[:grid] = false
# delete!(d, :axis)
# end
# for letter in (:x, :y, :z)
# asym = Symbol(letter, :axis)
# if haskey(d, asym) || d[asym] in (:none, nothing, false)
@@ -731,6 +833,13 @@ function preprocessArgs!(d::KW)
# end
# end
# handle axis args common to all axis
args = pop!(d, :axis, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
process_axis_arg!(d, arg, letter)
end
end
# handle axis args
for letter in (:x, :y, :z)
asym = Symbol(letter, :axis)
@@ -758,6 +867,32 @@ function preprocessArgs!(d::KW)
end
end
# fonts
for fontname in (:titlefont, :legendfont)
args = pop!(d, fontname, ())
for arg in wraptuple(args)
processFontArg!(d, fontname, arg)
end
end
# handle font args common to all axes
for fontname in (:tickfont, :guidefont)
args = pop!(d, fontname, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processFontArg!(d, Symbol(letter, fontname), arg)
end
end
end
# handle individual axes font args
for letter in (:x, :y, :z)
for fontname in (:tickfont, :guidefont)
args = pop!(d, Symbol(letter, fontname), ())
for arg in wraptuple(args)
processFontArg!(d, Symbol(letter, fontname), arg)
end
end
end
# handle line args
for arg in wraptuple(pop!(d, :line, ()))
processLineArg(d, arg)
@@ -822,6 +957,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)
@@ -834,28 +974,36 @@ end
# -----------------------------------------------------------------------------
"A special type that will break up incoming data into groups, and allow for easier creation of grouped plots"
type GroupBy
mutable struct GroupBy
groupLabels::Vector # length == numGroups
groupIds::Vector{Vector{Int}} # list of indices for each group
end
# this is when given a vector-type of values to group by
function extractGroupArgs(v::AVec, args...)
function extractGroupArgs(v::AVec, args...; legendEntry = string)
groupLabels = sort(collect(unique(v)))
n = length(groupLabels)
if n > 100
warn("You created n=$n groups... Is that intended?")
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...)
function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
groupLabels = sortedkeys(idxmap)
groupIds = VecI[collect(idxmap[k]) for k in groupLabels]
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
GroupBy(groupLabels, groupIds)
end
@@ -936,7 +1084,7 @@ function convertLegendValue(val::Symbol)
:best
elseif val in (:no, :none)
:none
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright)
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright)
val
else
error("Invalid symbol for legend: $val")
@@ -944,7 +1092,7 @@ function convertLegendValue(val::Symbol)
end
convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Void) = :none
convertLegendValue{S<:Real, T<:Real}(v::Tuple{S,T}) = v
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# -----------------------------------------------------------------------------
@@ -1018,6 +1166,12 @@ const _match_map = KW(
:top_margin => :margin,
:right_margin => :margin,
:bottom_margin => :margin,
:titlefontfamily => :fontfamily_subplot,
:legendfontfamily => :fontfamily_subplot,
:titlefontcolor => :foreground_color_subplot,
:legendfontcolor => :foreground_color_subplot,
:tickfontcolor => :foreground_color_text,
:guidefontcolor => :foreground_color_guide,
)
# these can match values from the parent container (axis --> subplot --> plot)
@@ -1029,6 +1183,9 @@ const _match_map2 = KW(
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_guide => :foreground_color_subplot,
:foreground_color_text => :foreground_color_subplot,
:fontfamily_subplot => :fontfamily,
:tickfontfamily => :fontfamily_subplot,
:guidefontfamily => :fontfamily_subplot,
)
# properly retrieve from plt.attr, passing `:match` to the correct key
@@ -1249,6 +1406,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
@@ -1318,12 +1477,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
@@ -1336,13 +1497,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)
+139 -43
View File
@@ -70,13 +70,16 @@ function process_axis_arg!(d::KW, arg, letter = "")
elseif arg == nothing
d[Symbol(letter,:ticks)] = []
elseif T <: Bool || arg in _allShowaxisArgs
d[Symbol(letter,:showaxis)] = showaxis(arg, letter)
elseif typeof(arg) <: Number
d[Symbol(letter,:rotation)] = arg
elseif typeof(arg) <: Function
d[Symbol(letter,:formatter)] = arg
else
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_axis))
warn("Skipped $(letter)axis arg $arg")
end
@@ -181,15 +184,27 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
end
# get a list of well-laid-out ticks
scaled_ticks = if ticks == nothing
optimize_ticks(
if ticks == nothing
scaled_ticks = optimize_ticks(
sf(amin),
sf(amax);
k_min = 5, # minimum number of ticks
k_min = 4, # minimum number of ticks
k_max = 8, # maximum number of ticks
)[1]
elseif typeof(ticks) <: Int
scaled_ticks, viewmin, viewmax = optimize_ticks(
sf(amin),
sf(amax);
k_min = ticks, # minimum number of ticks
k_max = ticks, # maximum number of ticks
k_ideal = ticks,
# `strict_span = false` rewards cases where the span of the
# chosen ticks is not too much bigger than amin - amax:
strict_span = false,
)
axis[:lims] = map(invscalefunc(scale), (viewmin, viewmax))
else
map(sf, filter(t -> amin <= t <= amax, ticks))
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end
unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
@@ -216,7 +231,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]
@@ -224,9 +239,14 @@ function get_ticks(axis::Axis)
# discrete ticks...
axis[:continuous_values], dvals
elseif ticks == :auto
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
elseif typeof(ticks) <: AVec
if ispolar(axis.sps[1]) && axis[:letter] == :x
#force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
else
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
end
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 +266,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])
# -------------------------------------------------------------------------
@@ -274,13 +298,13 @@ expand_extrema!(axis::Axis, ::Void) = axis[:extrema]
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
function expand_extrema!{MIN<:Number,MAX<:Number}(axis::Axis, v::Tuple{MIN,MAX})
function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
ex = axis[:extrema]
ex.emin = NaNMath.min(v[1], ex.emin)
ex.emax = NaNMath.max(v[2], ex.emax)
ex
end
function expand_extrema!{N<:Number}(axis::Axis, v::AVec{N})
function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
ex = axis[:extrema]
for vi in v
expand_extrema!(ex, vi)
@@ -331,7 +355,7 @@ function expand_extrema!(sp::Subplot, d::KW)
if fr == nothing && d[:seriestype] == :bar
fr = 0.0
end
if fr != nothing
if fr != nothing && !all3D(d)
axis = sp.attr[vert ? :yaxis : :xaxis]
if typeof(fr) <: Tuple
for fri in fr
@@ -349,13 +373,22 @@ function expand_extrema!(sp::Subplot, d::KW)
bw = d[:bar_width]
if bw == nothing
bw = d[:bar_width] = ignorenan_mean(diff(data))
bw = d[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
end
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end
# expand for heatmaps
if d[:seriestype] == :heatmap
for letter in (:x, :y)
data = d[letter]
axis = sp[Symbol(letter, "axis")]
scale = get(d, Symbol(letter, "scale"), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
end
function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax)
@@ -408,7 +441,16 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
if !isfinite(amin) && !isfinite(amax)
amin, amax = 0.0, 1.0
end
if should_widen
if ispolar(axis.sps[1])
if axis[:letter] == :x
amin, amax = 0, 2pi
elseif lims == :auto
#widen max radius so ticks dont overlap with theta axis
amin, amax + 0.1 * abs(amax - amin)
else
amin, amax
end
elseif should_widen
widen(amin, amax)
else
amin, amax
@@ -490,40 +532,94 @@ function axis_drawing_info(sp::Subplot)
ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
xspine_segs = Segments(2)
yspine_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
if xaxis[:showaxis]
if sp[:framestyle] != :grid
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
end
push!(xaxis_segs, (xmin, y1), (xmax, y1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(xticks) > 1
showticks = xticks[1] .!= 0
xticks = (xticks[1][showticks], xticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2), (xmax, y2)) # top spine
end
if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(ymin) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t2 = invf(f(ymax) - 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
push!(xspine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
# push!(xspine_segs, (xmin,ymax), (xmax,ymax)) # top spine
for xtick in xticks[1]
push!(xspine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
# push!(xspine_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, t1), (xtick, t2)) # vertical grid
for xtick in xticks[1]
if xaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
end
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end
end
# yaxis
if yaxis[:showaxis]
if sp[:framestyle] != :grid
x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
end
push!(yaxis_segs, (x1, ymin), (x1, ymax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin), (x2, ymax)) # right spine
end
if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(xmin) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t2 = invf(f(xmax) - 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
for ytick in yticks[1]
if yaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
end
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
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!(yspine_segs, (xmin,ymin), (xmin,ymax)) # left spine
# push!(yspine_segs, (xmax,ymin), (xmax,ymax)) # right spine
for ytick in yticks[1]
push!(yspine_segs, (xmin, ytick), (t1, ytick)) # left tick
# push!(yspine_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
end
end
xticks, yticks, xspine_segs, yspine_segs, xgrid_segs, ygrid_segs
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs
end
+9 -6
View File
@@ -1,12 +1,15 @@
immutable NoBackend <: AbstractBackend end
struct NoBackend <: AbstractBackend end
const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[]
const _initialized_backends = Set{Symbol}()
"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")
@@ -15,7 +18,7 @@ macro init_backend(s)
sym = Symbol(str)
T = Symbol(string(s) * "Backend")
esc(quote
immutable $T <: AbstractBackend end
struct $T <: AbstractBackend end
export $sym
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
backend_name(::$T) = Symbol($str)
@@ -48,8 +51,8 @@ _series_updated(plt::Plot, series::Series) = nothing
_before_layout_calcs(plt::Plot) = nothing
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefontsize] * pt
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefontsize] * pt
"Returns the (width,height) of a text label."
function text_size(lablen::Int, sz::Number, rot::Number = 0)
@@ -90,7 +93,7 @@ function tick_padding(axis::Axis)
# hgt
# get the height of the rotated label
text_size(longest_label, axis[:tickfont].pointsize, rot)[2]
text_size(longest_label, axis[:tickfontsize], rot)[2]
end
end
@@ -120,7 +123,7 @@ _update_plot_object(plt::Plot) = nothing
# ---------------------------------------------------------
type CurrentBackend
mutable struct CurrentBackend
sym::Symbol
pkg::AbstractBackend
end
+85 -35
View File
@@ -9,6 +9,10 @@ TODO
* fix units in all visuals (e.g dotted lines, marker scale, surfaces)
=#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "glvisualize.jl"))
end
const _glvisualize_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
@@ -20,10 +24,13 @@ const _glvisualize_attr = merge_with_base_supported([
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:title, :title_location,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:titlefontsize, :titlefontcolor,
:legendfontsize, :legendfontcolor,
:tickfontsize,
:guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :colorbar,
:marker_z,
@@ -39,7 +46,9 @@ const _glvisualize_attr = merge_with_base_supported([
:clims,
:inset_subplots,
:dpi,
:hover
:hover,
:framestyle,
:tick_direction,
])
const _glvisualize_seriestype = [
:path, :shape,
@@ -67,9 +76,9 @@ function _initialize_backend(::GLVisualizeBackend; kw...)
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
Plots.slice_arg{C<:Colorant}(img::Matrix{C}, idx::Int) = img
Plots.slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported{C<:Colorant}(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) = true
is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
const GL = Plots
end
@@ -212,13 +221,13 @@ function extract_limits(sp, d, kw_args)
nothing
end
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vec::T) = vec
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, s::Number) = T(s)
to_vec(::Type{T}, vec::T) where {T <: StaticArrays.StaticVector} = vec
to_vec(::Type{T}, s::Number) where {T <: StaticArrays.StaticVector} = T(s)
to_vec{T <: StaticArrays.StaticVector{2}}(::Type{T}, vec::StaticArrays.StaticVector{3}) = T(vec[1], vec[2])
to_vec{T <: StaticArrays.StaticVector{3}}(::Type{T}, vec::StaticArrays.StaticVector{2}) = T(vec[1], vec[2], 0)
to_vec(::Type{T}, vec::StaticArrays.StaticVector{3}) where {T <: StaticArrays.StaticVector{2}} = T(vec[1], vec[2])
to_vec(::Type{T}, vec::StaticArrays.StaticVector{2}) where {T <: StaticArrays.StaticVector{3}} = T(vec[1], vec[2], 0)
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
to_vec(::Type{T}, vecs::AbstractVector) where {T <: StaticArrays.StaticVector} = map(x-> to_vec(T, x), vecs)
function extract_marker(d, kw_args)
dim = Plots.is3d(d) ? 3 : 2
@@ -273,7 +282,7 @@ end
function extract_surface(d)
map(_extract_surface, (d[:x], d[:y], d[:z]))
end
function topoints{P}(::Type{P}, array)
function topoints(::Type{P}, array) where P
[P(x) for x in zip(array...)]
end
function extract_points(d)
@@ -281,7 +290,7 @@ function extract_points(d)
array = (d[:x], d[:y], d[:z])[1:dim]
topoints(Point{dim, Float32}, array)
end
function make_gradient{C <: Colorant}(grad::Vector{C})
function make_gradient(grad::Vector{C}) where C <: Colorant
grad
end
function make_gradient(grad::ColorGradient)
@@ -336,7 +345,7 @@ function extract_color(d, sym)
end
gl_color(c::PlotUtils.ColorGradient) = c.colors
gl_color{T<:Colorant}(c::Vector{T}) = c
gl_color(c::Vector{T}) where {T<:Colorant} = c
gl_color(c::RGBA{Float32}) = c
gl_color(c::Colorant) = RGBA{Float32}(c)
@@ -603,10 +612,10 @@ end
pointsize(font) = font.pointsize * 2
function draw_ticks(
axis, ticks, isx, lims, m, text = "",
axis, ticks, isx, isorigin, lims, m, text = "",
positions = Point2f0[], offsets=Vec2f0[]
)
sz = pointsize(axis[:tickfont])
sz = pointsize(tickfont(axis))
atlas = GLVisualize.get_texture_atlas()
font = GLVisualize.defaultfont()
@@ -621,7 +630,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)
@@ -677,7 +690,7 @@ function text_model(font, pivot)
end
end
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
xticks, yticks, xspine_segs, yspine_segs, xgrid_segs, ygrid_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]
xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
@@ -702,35 +715,73 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
spine = draw_grid_lines(sp, yspine_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine)
end
if sp[:framestyle] in (:zerolines, :grid)
if alpha(xaxis[:foreground_color_grid]) > 0
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_grid]) > 0
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, spine)
end
else
if alpha(xaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine)
end
end
fcolor = Plots.gl_color(xaxis[:foreground_color_axis])
xlim = Plots.axis_limits(xaxis)
ylim = Plots.axis_limits(yaxis)
if !(xaxis[:ticks] in (nothing, false, :none))
if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) && xaxis[:showaxis]
ticklabels = map(model) do m
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(xaxis, xticks, true, ylim, m)
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(
yaxis, yticks, false, xlim, m,
t, positions, offsets
)
t, positions, offsets = draw_ticks(xaxis, xticks, true, sp[:framestyle] == :origin, ylim, m)
end
kw_args = Dict{Symbol, Any}(
:position => map(x-> x[2], ticklabels),
:offset => map(last, ticklabels),
:color => fcolor,
:relative_scale => pointsize(xaxis[:tickfont]),
:relative_scale => pointsize(tickfont(xaxis)),
:scale_primitive => false
)
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end
if !(yaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) && yaxis[:showaxis]
ticklabels = map(model) do m
mirror = yaxis[:mirror]
t, positions, offsets = draw_ticks(yaxis, yticks, false, sp[:framestyle] == :origin, xlim, m)
end
kw_args = Dict{Symbol, Any}(
:position => map(x-> x[2], ticklabels),
:offset => map(last, ticklabels),
:color => fcolor,
:relative_scale => pointsize(tickfont(xaxis)),
:scale_primitive => false
)
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end
xbc = Colors.color(Plots.gl_color(xaxis[:foreground_color_border]))
ybc = Colors.color(Plots.gl_color(yaxis[:foreground_color_border]))
intensity = sp[:framestyle] == :semi ? 0.5f0 : 1.0f0
if sp[:framestyle] in (:box, :semi)
xborder = draw_grid_lines(sp, xborder_segs, intensity, :solid, model, RGBA(xbc, intensity))
yborder = draw_grid_lines(sp, yborder_segs, intensity, :solid, model, RGBA(ybc, intensity))
push!(axis_vis, xborder, yborder)
end
area_w = GeometryTypes.widths(area)
if sp[:title] != ""
tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title])
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, tf.rotation, color)
tf = titlefont(sp)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, tf.rotation, tf.color)
xy = Point2f0(area.w/2, area_w[2] + pointsize(tf)/2)
kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
extract_font(font, kw)
@@ -738,9 +789,9 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
push!(axis_vis, glvisualize_text(xy, t, kw))
end
if xaxis[:guide] != ""
tf = xaxis[:guidefont]; color = gl_color(xaxis[:foreground_color_guide])
tf = guidefont(xaxis)
xy = Point2f0(area.w/2, - pointsize(tf)/2)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :bottom, tf.rotation, color)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :bottom, tf.rotation, tf.color)
kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
t = PlotText(xaxis[:guide], font)
extract_font(font, kw)
@@ -748,8 +799,8 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
end
if yaxis[:guide] != ""
tf = yaxis[:guidefont]; color = gl_color(yaxis[:foreground_color_guide])
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, 90f0, color)
tf = guidefont(yaxis)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, 90f0, tf.color)
xy = Point2f0(-pointsize(tf)/2, area.h/2)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>true)
t = PlotText(yaxis[:guide], font)
@@ -1168,7 +1219,7 @@ function gl_image(img, kw_args)
visualize(img, Style(:default), kw_args)
end
function handle_segment{P}(lines, line_segments, points::Vector{P}, segment)
function handle_segment(lines, line_segments, points::Vector{P}, segment) where P
(isempty(segment) || length(segment) < 2) && return
if length(segment) == 2
append!(line_segments, view(points, segment))
@@ -1435,9 +1486,8 @@ function make_label(sp, series, i)
else
series[:label]
end
color = sp[:foreground_color_legend]
ft = sp[:legendfont]
font = Plots.Font(ft.family, ft.pointsize, :left, :bottom, 0.0, color)
ft = legendfont(sp)
font = Plots.Font(ft.family, ft.pointsize, :left, :bottom, 0.0, ft.color)
xy = Point2f0(w+gap, 0.0)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>false)
extract_font(font, kw)
+313 -166
View File
@@ -3,6 +3,9 @@
# significant contributions by @jheinen
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "gr.jl"))
end
const _gr_attr = merge_with_base_supported([
:annotations,
@@ -19,10 +22,17 @@ const _gr_attr = merge_with_base_supported([
:layout,
:title, :window_title,
:guide, :lims, :ticks, :scale, :flip,
:tickfont, :guidefont, :legendfont,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
:legendfontrotation, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
:tickfontrotation, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
:guidefontrotation, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :levels,
:fill_z, :line_z, :marker_z, :levels,
:ribbon, :quiver,
:orientation,
:overwrite_figure,
@@ -32,6 +42,9 @@ const _gr_attr = merge_with_base_supported([
:inset_subplots,
:bar_width,
:arrow,
:framestyle,
:tick_direction,
:camera,
])
const _gr_seriestype = [
:path, :scatter,
@@ -199,35 +212,62 @@ function gr_text(x, y, s)
end
end
function gr_polaraxes(rmin, rmax)
function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
GR.savestate()
GR.setlinetype(GR.LINETYPE_SOLID)
GR.setlinecolorind(88)
tick = 0.5 * GR.tick(rmin, rmax)
n = round(Int, (rmax - rmin) / tick + 0.5)
for i in 0:n
r = float(i) / n
if i % 2 == 0
GR.setlinecolorind(88)
if i > 0
GR.drawarc(-r, r, -r, r, 0, 359)
end
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
x, y = GR.wctondc(0.05, r)
GR.text(x, y, string(signif(rmin + i * tick, 12)))
else
GR.setlinecolorind(90)
GR.drawarc(-r, r, -r, r, 0, 359)
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
α = 0:45:315
a = α .+ 90
sinf = sind.(a)
cosf = cosd.(a)
rtick_values, rtick_labels = get_ticks(yaxis)
#draw angular grid
if xaxis[:grid]
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
GR.settransparency(xaxis[:gridalpha])
for i in 1:length(α)
GR.polyline([sinf[i], 0], [cosf[i], 0])
end
end
for α in 0:45:315
a = α + 90
sinf = sin(a * pi / 180)
cosf = cos(a * pi / 180)
GR.polyline([sinf, 0], [cosf, 0])
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
x, y = GR.wctondc(1.1 * sinf, 1.1 * cosf)
GR.textext(x, y, string(α, "^o"))
#draw radial grid
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
GR.settransparency(yaxis[:gridalpha])
for i in 1:length(rtick_values)
r = (rtick_values[i] - rmin) / (rmax - rmin)
if r <= 1.0 && r >= 0.0
GR.drawarc(-r, r, -r, r, 0, 359)
end
end
GR.drawarc(-1, 1, -1, 1, 0, 359)
end
#prepare to draw ticks
GR.settransparency(1)
GR.setlinecolorind(90)
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
#draw angular ticks
if xaxis[:showaxis]
GR.drawarc(-1, 1, -1, 1, 0, 359)
for i in 1:length(α)
x, y = GR.wctondc(1.1 * sinf[i], 1.1 * cosf[i])
GR.textext(x, y, string((360-α[i])%360, "^o"))
end
end
#draw radial ticks
if yaxis[:showaxis]
for i in 1:length(rtick_values)
r = (rtick_values[i] - rmin) / (rmax - rmin)
if r <= 1.0 && r >= 0.0
x, y = GR.wctondc(0.05, r)
gr_text(x, y, _cycle(rtick_labels, i))
end
end
end
GR.restorestate()
end
@@ -263,17 +303,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) = α
@@ -326,20 +367,19 @@ 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.setscale(0)
gr_colorbar(series[:subplot])
end
end
# ---------------------------------------------------------
@@ -406,6 +446,9 @@ function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, vi
viewport[3] = 0.5 * (vp[3] + vp[4] - extent)
viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
end
if hascolorbar(sp)
viewport[2] -= 0.1
end
viewport
end
@@ -441,12 +484,17 @@ function gr_set_viewport_polar()
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
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.setscale(0)
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])
@@ -474,7 +522,7 @@ function gr_legend_pos(s::Symbol,w,h)
(xpos,ypos)
end
function gr_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T},w,h)
function gr_legend_pos(v::Tuple{S,T},w,h) where {S<:Real, T<:Real}
xpos = v[1] * (viewport_plotarea[2] - viewport_plotarea[1]) + viewport_plotarea[1]
ypos = v[2] * (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_plotarea[3]
(xpos,ypos)
@@ -539,40 +587,89 @@ function gr_display(plt::Plot)
end
function gr_set_xticks_font(sp)
flip = sp[:yaxis][:flip]
mirror = sp[:xaxis][:mirror]
gr_set_font(tickfont(sp[:xaxis]),
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = (mirror ? :bottom : :top),
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(tickfont(sp[:yaxis]),
halign = (mirror ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
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)
@@ -607,14 +704,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
@@ -628,11 +722,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
end
if cmap && sp[:colorbar] != :none
# note: add extra midpadding on the right for the colorbar
viewport_plotarea[2] -= 0.1
end
# set our plot area view
gr_set_viewport_plotarea()
@@ -675,8 +764,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
# draw the axes
gr_set_font(xaxis[:tickfont])
gr_set_textcolor(xaxis[:foreground_color_text])
gr_set_font(tickfont(xaxis))
GR.setlinewidth(1)
if is3d(sp)
@@ -686,7 +774,7 @@ 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, round.(Int, sp[:camera])...)
xtick = GR.tick(xmin, xmax) / 2
ytick = GR.tick(ymin, ymax) / 2
ztick = GR.tick(zmin, zmax) / 2
@@ -701,16 +789,16 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif ispolar(sp)
r = gr_set_viewport_polar()
rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
# rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax)
#rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax, sp)
elseif draw_axes
if xmax > xmin && ymax > ymin
GR.setwindow(xmin, xmax, ymin, ymax)
end
xticks, yticks, xspine_segs, yspine_segs, xgrid_segs, ygrid_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
@@ -728,81 +816,119 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
GR.settransparency(1.0)
# spine (border) and tick marks
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(xspine_segs)...)
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(yspine_segs)...)
# axis lines
if xaxis[:showaxis]
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(xspine_segs)...)
end
if yaxis[:showaxis]
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(yspine_segs)...)
end
GR.setclip(1)
if !(xticks in (nothing, false))
# axis ticks
if xaxis[:showaxis]
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)...)
end
if yaxis[:showaxis]
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)...)
end
GR.setclip(1)
# tick marks
if !(xticks in (:none, nothing, false)) && xaxis[:showaxis]
# 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)) && yaxis[:showaxis]
# 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
# add the guides
GR.savestate()
if sp[:title] != ""
gr_set_font(sp[:titlefont])
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
gr_set_textcolor(sp[:foreground_color_title])
gr_text(gr_view_xcenter(), viewport_subplot[4], sp[:title])
gr_set_font(titlefont(sp))
loc = sp[:title_location]
if loc == :left
xpos = viewport_plotarea[1]
halign = GR.TEXT_HALIGN_LEFT
elseif loc == :right
xpos = viewport_plotarea[2]
halign = GR.TEXT_HALIGN_RIGHT
else
xpos = gr_view_xcenter()
halign = GR.TEXT_HALIGN_CENTER
end
GR.settextalign(halign, GR.TEXT_VALIGN_TOP)
gr_text(xpos, viewport_subplot[4], sp[:title])
end
if xaxis[:guide] != ""
gr_set_font(xaxis[:guidefont])
gr_set_font(guidefont(xaxis))
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
gr_set_textcolor(xaxis[:foreground_color_guide])
gr_text(gr_view_xcenter(), viewport_subplot[3], xaxis[:guide])
end
if yaxis[:guide] != ""
gr_set_font(yaxis[:guidefont])
gr_set_font(guidefont(yaxis))
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.setcharup(-1, 0)
gr_set_textcolor(yaxis[:foreground_color_guide])
gr_text(viewport_subplot[1], gr_view_ycenter(), yaxis[:guide])
end
GR.restorestate()
gr_set_font(xaxis[:tickfont])
gr_set_font(tickfont(xaxis))
# 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]
@@ -811,6 +937,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()
@@ -845,26 +975,32 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if st in (:path, :scatter)
if length(x) > 1
lz = series[:line_z]
segments_iterator = if lz != nothing && length(lz) > 1
[i:(i + 1) for i in 1:(length(x) - 1)]
else
iter_segments(x, y)
end
# do area fill
if frng != nothing
GR.setfillintstyle(GR.INTSTYLE_SOLID)
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
for (i,rng) in enumerate(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, rng) in enumerate(segments_iterator)
gr_set_fillcolor(get_fillcolor(sp, series, i))
fx = _cycle(x, vcat(rng, reverse(rng)))
fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
series[:fillalpha] != nothing && GR.settransparency(series[:fillalpha])
GR.fillarea(fx, fy)
end
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, rng) in enumerate(segments_iterator)
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
gr_polyline(x[rng], y[rng]; arrowside = arrowside)
end
end
end
@@ -873,16 +1009,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
zmin, zmax = extrema(series[:marker_z])
GR.setspace(zmin, zmax, 0, 90)
end
gr_draw_markers(series, x, y)
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]
@@ -892,11 +1023,14 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
else
GR.setlinetype(gr_linetype[series[:linestyle]])
GR.setlinewidth(max(0, series[:linewidth] / (sum(gr_plot_size) * 0.001)))
GR.contour(x, y, h, z, 1000)
end
# create the colorbar of contour levels
if sp[:colorbar] != :none
if cmap
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_viewport_cmap(sp)
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
GR.setwindow(xmin, xmax, zmin, zmax)
@@ -917,16 +1051,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setfillcolorind(0)
GR.surface(x, y, z, GR.OPTION_FILLED_MESH)
end
cmap && gr_colorbar(sp)
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]
@@ -936,21 +1064,28 @@ 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)
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)
lz = series[:line_z]
segments_iterator = if lz != nothing && length(lz) > 1
[i:(i + 1) for i in 1:(length(x) - 1)]
else
iter_segments(x, y, z)
end
for (i, rng) in enumerate(segments_iterator)
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
GR.polyline3d(x[rng], y[rng], z[rng])
end
end
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
@@ -1002,21 +1137,21 @@ 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
@@ -1043,6 +1178,13 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_text(GR.wctondc(xi, yi)..., str)
end
# draw the colorbar
if cmap && st != :contour # special colorbar with steps is drawn for contours
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.settransparency(1)
gr_colorbar(sp, clims)
end
GR.restorestate()
end
@@ -1052,7 +1194,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.savestate()
GR.selntran(0)
GR.setscale(0)
gr_set_font(sp[:legendfont])
gr_set_font(legendfont(sp))
w = 0
i = 0
n = 0
@@ -1070,23 +1212,22 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
else
lab = series[:label]
end
tbx, tby = gr_inqtext(0, 0, lab)
tbx, tby = gr_inqtext(0, 0, string(lab))
w = max(w, tbx[3] - tbx[1])
end
if w > 0
dy = _gr_point_mult[1] * sp[:legendfont].pointsize * 1.75
dy = _gr_point_mult[1] * sp[:legendfontsize] * 1.75
h = dy*n
(xpos,ypos) = gr_legend_pos(sp[:legend],w,h)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_set_fillcolor(sp[:background_color_legend])
GR.fillrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
GR.setlinetype(1)
GR.setlinewidth(1)
gr_set_line(1, :solid, sp[:foreground_color_legend])
GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
i = 0
if sp[:legendtitle] != nothing
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
gr_set_textcolor(sp[:foreground_color_legend])
gr_set_textcolor(sp[:legendfontcolor])
GR.settransparency(1)
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
ypos -= dy
@@ -1094,10 +1235,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]
@@ -1128,8 +1269,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
lab = series[:label]
end
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
gr_set_textcolor(sp[:foreground_color_legend])
gr_text(xpos, ypos, lab)
gr_set_textcolor(sp[:legendfontcolor])
gr_text(xpos, ypos, string(lab))
ypos -= dy
end
end
@@ -1187,12 +1328,18 @@ for (mime, fmt) in _gr_mimeformats
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend})
GR.emergencyclosegks()
filepath = tempname() * "." * $fmt
env = get(ENV, "GKSwstype", "0")
ENV["GKSwstype"] = $fmt
ENV["GKS_FILEPATH"] = filepath
gr_display(plt)
GR.emergencyclosegks()
write(io, readstring(filepath))
rm(filepath)
if env != "0"
ENV["GKSwstype"] = env
else
pop!(ENV,"GKSwstype")
end
end
end
+12 -9
View File
@@ -28,14 +28,17 @@ Read from .hdf5 file using:
- Should be reliable for archival purposes.
==#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
end
import FixedPointNumbers: N0f8 #In core Julia
#Dispatch types:
immutable HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
immutable HDF5CTuple; end #Identifies a "complex" tuple structure
struct HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
struct HDF5CTuple; end #Identifies a "complex" tuple structure
type HDF5Plot_PlotRef
mutable struct HDF5Plot_PlotRef
ref::Union{Plot, Void}
end
@@ -128,7 +131,7 @@ function _hdf5_merge!(dest::Dict, src::Dict)
_hdf5_merge!(dest[k].d, v.d)
else
dest[k] = v
end
end
end
return
end
@@ -276,11 +279,11 @@ function _hdf5plot_overwritetype(grp, T::Type) #Write directly to group
HDF5.a_delete(grp, _hdf5plot_datatypeid)
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype{T<:Any}(grp, ::Type{Array{T}})
function _hdf5plot_writetype(grp, ::Type{Array{T}}) where T<:Any
tstr = HDF5PLOT_MAP_TELEM2STR[Array] #ANY
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype{T<:BoundingBox}(grp, ::Type{T})
function _hdf5plot_writetype(grp, ::Type{T}) where T<:BoundingBox
tstr = HDF5PLOT_MAP_TELEM2STR[BoundingBox]
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
@@ -305,7 +308,7 @@ function _hdf5plot_gwrite(grp, k::String, v) #Default
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
function _hdf5plot_gwrite{T<:Number}(grp, k::String, v::Array{T}) #Default for arrays
function _hdf5plot_gwrite(grp, k::String, v::Array{T}) where T<:Number #Default for arrays
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
@@ -355,7 +358,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Colorant)
_hdf5plot_gwrite(grp, k, ARGB{N0f8}(v))
end
#Custom vector (when not using simple numeric type):
function _hdf5plot_gwritearray{T}(grp, k::String, v::Array{T})
function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
if "annotations" == k;
return #Hack. Does not yet support annotations.
end
@@ -380,7 +383,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Extrema)
grp[k] = [v.emin, v.emax]
_hdf5plot_writetype(grp, k, Extrema)
end
function _hdf5plot_gwrite{T}(grp, k::String, v::Length{T})
function _hdf5plot_gwrite(grp, k::String, v::Length{T}) where T
grp[k] = v.value
_hdf5plot_writetype(grp, k, [HDF5PLOT_MAP_TELEM2STR[Length], string(T)])
end
+28 -21
View File
@@ -13,6 +13,10 @@ Add in functionality to Plots.jl:
:aspect_ratio,
=#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "inspectdr.jl"))
end
# ---------------------------------------------------------------------------
#TODO: remove features
const _inspectdr_attr = merge_with_base_supported([
@@ -28,10 +32,13 @@ const _inspectdr_attr = merge_with_base_supported([
:markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:title, :title_location,
:window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :legend, #:colorbar,
# :marker_z,
# :line_z,
@@ -131,7 +138,7 @@ end
function _inspectdr_getscale(s::Symbol, yaxis::Bool)
#TODO: Support :asinh, :sqrt
kwargs = yaxis? (:tgtmajor=>8, :tgtminor=>2): () #More grid lines on y-axis
kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis
if :log2 == s
return InspectDR.AxisScale(:log2; kwargs...)
elseif :log10 == s
@@ -163,7 +170,7 @@ function _initialize_backend(::InspectDRBackend; kw...)
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
type InspecDRPlotRef
mutable struct InspecDRPlotRef
mplot::Union{Void, InspectDR.Multiplot}
gui::Union{Void, InspectDR.GtkPlot}
end
@@ -172,7 +179,7 @@ function _initialize_backend(::InspectDRBackend; kw...)
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
_inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed? nothing: gplot)
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
end
end
@@ -235,13 +242,13 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
#Don't do anything without a "subplot" object: Will process later.
if nothing == plot; return; end
_vectorize(v) = isa(v, Vector)? v: collect(v) #InspectDR only supports vectors
_vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x = _vectorize(series[:x]); y = _vectorize(series[:y])
#No support for polar grid... but can still perform polar transformation:
if ispolar(sp)
Θ = x; r = y
x = r.*cos(Θ); y = r.*sin(Θ)
x = r.*cos.(Θ); y = r.*sin.(Θ)
end
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
@@ -278,7 +285,7 @@ For st in :shape:
end
end
i = (nmax >= 2? div(nmax, 2): nmax) #Must pick one set of colors for legend
i = (nmax >= 2 ? div(nmax, 2) : nmax) #Must pick one set of colors for legend
if i > 1 #Add dummy waveform for legend entry:
linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
@@ -296,7 +303,7 @@ For st in :shape:
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth:
_style = (0==linewidth? :none: series[:linestyle])
_style = (0==linewidth ? :none : series[:linestyle])
wfrm = InspectDR.add(plot, x, y, id=series[:label])
wfrm.line = InspectDR.line(
style = _style,
@@ -369,24 +376,24 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l[:font_title] = InspectDR.Font(sp[:titlefont].family,
_inspectdr_mapptsize(sp[:titlefont].pointsize),
color = _inspectdr_mapcolor(sp[:foreground_color_title])
l[:font_title] = InspectDR.Font(sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:titlefontcolor])
)
#Cannot independently control fonts of axes with InspectDR:
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefont].family,
_inspectdr_mapptsize(xaxis[:guidefont].pointsize),
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide])
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
)
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfont].family,
_inspectdr_mapptsize(xaxis[:tickfont].pointsize),
color = _inspectdr_mapcolor(xaxis[:foreground_color_text])
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:tickfontcolor])
)
l[:enable_legend] = (sp[:legend] != :none)
#l[:halloc_legend] = 150 #TODO: compute???
l[:font_legend] = InspectDR.Font(sp[:legendfont].family,
_inspectdr_mapptsize(sp[:legendfont].pointsize),
color = _inspectdr_mapcolor(sp[:foreground_color_legend])
l[:font_legend] = InspectDR.Font(sp[:legendfontfamily],
_inspectdr_mapptsize(sp[:legendfontsize]),
color = _inspectdr_mapcolor(sp[:legendfontcolor])
)
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
end
+83 -7
View File
@@ -2,6 +2,10 @@
# significant contributions by: @pkofod
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pgfplots.jl"))
end
const _pgfplots_attr = merge_with_base_supported([
:annotations,
# :background_color_legend,
@@ -31,10 +35,13 @@ const _pgfplots_attr = merge_with_base_supported([
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
:framestyle,
:camera,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
@@ -79,6 +86,7 @@ const _pgfplots_markers = KW(
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*",
:hline => "-"
)
const _pgfplots_legend_pos = KW(
@@ -86,6 +94,7 @@ const _pgfplots_legend_pos = KW(
:bottomright => "south east",
:topright => "north east",
:topleft => "north west",
:outertopright => "outer north east",
)
@@ -106,6 +115,18 @@ const _pgf_annotation_halign = KW(
:right => "left"
)
const _pgf_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
const _pgf_framestyle_defaults = Dict(:semi => :box)
function pgf_framestyle(style::Symbol)
if style in _pgf_framestyles
return style
else
default_style = get(_pgf_framestyle_defaults, style, :axes)
warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
default_style
end
end
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
@@ -187,6 +208,9 @@ function pgf_series(sp::Subplot, series::Series)
# add to legend?
if sp[:legend] != :none && should_add_to_legend(series)
kw[:legendentry] = d[:label]
if st == :shape || d[:fillrange] != nothing
push!(style, "area legend")
end
else
push!(style, "forget plot")
end
@@ -200,6 +224,9 @@ function pgf_series(sp::Subplot, series::Series)
# If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation
d[:x], d[:y], d[:marker_z]
elseif ispolar(sp)
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
rad2deg.(theta), r
else
d[:x], d[:y]
end
@@ -245,6 +272,9 @@ function pgf_axis(sp::Subplot, letter)
style = []
kw = KW()
# set to supported framestyle
framestyle = pgf_framestyle(sp[:framestyle])
# axis guide
kw[Symbol(letter,:label)] = axis[:guide]
@@ -262,27 +292,65 @@ function pgf_axis(sp::Subplot, letter)
end
# ticks on or off
if axis[:ticks] in (nothing, false)
if axis[:ticks] in (nothing, false) || framestyle == :none
push!(style, "$(letter)majorticks=false")
end
# grid on or off
if axis[:grid]
if axis[:grid] && framestyle != :none
push!(style, "$(letter)majorgrids = true")
else
push!(style, "$(letter)majorgrids = false")
end
# limits
# TODO: support zlims
if letter != :z
lims = axis_limits(axis)
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :auto))
if !(axis[:ticks] in (nothing, false, :none)) && framestyle != :none
ticks = get_ticks(axis)
push!(style, string(letter, "tick = {", join(ticks[1],","), "}"))
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}"))
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = String[begin
base, power = split(label, "^")
power = string("{", power, "}")
string(base, "^", power)
end for label in ticks[2]]
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
elseif axis[:showaxis]
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
else
push!(style, string(letter, "ticklabels = {}"))
end
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
end
# framestyle
if framestyle in (:axes, :origin)
axispos = framestyle == :axes ? "left" : "middle"
# the * after lines disables the arrows at the axes
push!(style, string("axis lines* = ", axispos))
end
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {color = black, draw opacity=1.0, line width=0.5), solid}}"))
end
if !axis[:showaxis]
push!(style, "separate axis lines")
end
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
end
# return the style list and KW args
@@ -338,9 +406,17 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:legendPos] = _pgfplots_legend_pos[legpos]
end
if is3d(sp)
azim, elev = sp[:camera]
kw[:view] = "{$(azim)}{$(elev)}"
end
axisf = PGFPlots.Axis
if sp[:projection] == :polar
axisf = PGFPlots.PolarAxis
#make radial axis vertical
kw[:xmin] = 90
kw[:xmax] = 450
end
# Search series for any gradient. In case one series uses a gradient set
+112 -36
View File
@@ -1,6 +1,10 @@
# https://plot.ly/javascript/getting-started
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotly.jl"))
end
const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
@@ -15,7 +19,12 @@ const _plotly_attr = merge_with_base_supported([
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
:title, :title_location, :titlefont,
:title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
@@ -33,6 +42,9 @@ const _plotly_attr = merge_with_base_supported([
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
:camera,
])
const _plotly_seriestype = [
@@ -47,6 +59,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
# --------------------------------------------------------------------------------------
@@ -108,7 +131,7 @@ const _plotly_legend_pos = KW(
)
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
plotly_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T}) = v
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
function plotly_font(font::Font, color = font.color)
KW(
@@ -212,13 +235,20 @@ end
function plotly_axis(axis::Axis, sp::Subplot)
letter = axis[:letter]
framestyle = sp[:framestyle]
ax = KW(
:visible => framestyle != :none,
:title => axis[:guide],
:showgrid => axis[:grid],
:gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
:gridwidth => axis[:gridlinewidth],
:zeroline => false,
:ticks => "inside",
:zeroline => framestyle == :zerolines,
:zerolinecolor => rgba_string(axis[:foreground_color_axis]),
:showline => framestyle in (:box, :axes) && axis[:showaxis],
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks => axis[:tick_direction] == :out ? "outside" : "inside",
:mirror => framestyle == :box,
:showticklabels => axis[:showaxis],
)
if letter in (:x,:y)
@@ -227,20 +257,16 @@ function plotly_axis(axis::Axis, sp::Subplot)
end
ax[:tickangle] = -axis[:rotation]
lims = axis_limits(axis)
ax[:range] = map(scalefunc(axis[:scale]), lims)
if !(axis[:ticks] in (nothing, :none))
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
ax[:titlefont] = plotly_font(guidefont(axis))
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
ax[:tickcolor] = rgba_string(axis[:foreground_color_axis])
ax[:tickfont] = plotly_font(tickfont(axis))
ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# lims
lims = axis[:lims]
if lims != :auto && limsType(lims) == :limits
ax[:range] = map(scalefunc(axis[:scale]), lims)
end
# flip
if axis[:flip]
ax[:autorange] = "reversed"
@@ -263,6 +289,23 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:showgrid] = false
end
ax
end
function plotly_polaraxis(axis::Axis)
ax = KW(
:visible => axis[:showaxis],
:showline => axis[:grid],
)
if axis[:letter] == :x
ax[:range] = rad2deg.(axis_limits(axis))
else
ax[:range] = axis_limits(axis)
ax[:orientation] = -90
end
ax
end
@@ -293,19 +336,36 @@ function plotly_layout(plt::Plot)
0.5 * (left(bb) + right(bb))
end
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
titlefont = font(sp[:titlefont], :top, sp[:foreground_color_title])
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont)))
title_font = font(titlefont(sp), :top)
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
end
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
# set to supported framestyle
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
# if any(is3d, seriesargs)
if is3d(sp)
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
d_out[:scene] = KW(
Symbol("xaxis$spidx") => plotly_axis(sp[:xaxis], sp),
Symbol("yaxis$spidx") => plotly_axis(sp[:yaxis], sp),
Symbol("zaxis$spidx") => plotly_axis(sp[:zaxis], sp),
#2.6 multiplier set camera eye such that whole plot can be seen
:camera => KW(
:eye => KW(
:x => cosd(azim)*sind(theta)*2.6,
:y => sind(azim)*sind(theta)*2.6,
:z => cosd(theta)*2.6,
),
),
)
elseif ispolar(sp)
d_out[Symbol("angularaxis$spidx")] = plotly_polaraxis(sp[:xaxis])
d_out[Symbol("radialaxis$spidx")] = plotly_polaraxis(sp[:yaxis])
else
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
@@ -318,7 +378,7 @@ function plotly_layout(plt::Plot)
d_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]),
:font => plotly_font(legendfont(sp)),
:x => xpos,
:y => ypos
)
@@ -406,7 +466,7 @@ end
plotly_data(v) = collect(v)
plotly_data(surf::Surface) = surf.surf
plotly_data{R<:Rational}(v::AbstractArray{R}) = float(v)
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
plotly_surface_data(series::Series, a::AbstractVector) = a
plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false)
@@ -438,7 +498,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)
@@ -462,7 +523,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)
@@ -486,7 +547,7 @@ function plotly_series(plt::Plot, series::Series)
d_out[:type] = "heatmap"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:showscale] = sp[:legend] != :none
d_out[:showscale] = hascolorbar(sp)
elseif st == :contour
d_out[:type] = "contour"
@@ -495,7 +556,7 @@ function plotly_series(plt::Plot, series::Series)
d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
d_out[:showscale] = sp[:legend] != :none
d_out[:showscale] = hascolorbar(sp)
elseif st in (:surface, :wireframe)
d_out[:type] = "surface"
@@ -515,7 +576,7 @@ function plotly_series(plt::Plot, series::Series)
if series[:fill_z] != nothing
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
end
d_out[:showscale] = sp[:legend] != :none
d_out[:showscale] = hascolorbar(sp)
end
elseif st == :pie
@@ -553,14 +614,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
@@ -587,11 +652,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
@@ -644,8 +719,9 @@ end
function plotly_polar!(d_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(series[:subplot])
d_out[:t] = rad2deg(pop!(d_out, :x))
d_out[:r] = pop!(d_out, :y)
theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
d_out[:t] = rad2deg.(theta)
d_out[:r] = r
end
end
@@ -674,7 +750,7 @@ end
const _use_remote = Ref(false)
function html_head(plt::Plot{PlotlyBackend})
jsfilename = _use_remote[] ? _plotly_js_path_remote : _plotly_js_path
jsfilename = _use_remote[] ? _plotly_js_path_remote : ("file://" * _plotly_js_path)
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
"<script src=\"$jsfilename\"></script>"
end
+6 -1
View File
@@ -1,3 +1,6 @@
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
end
# https://github.com/spencerlyon2/PlotlyJS.jl
@@ -85,7 +88,8 @@ end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
prepare_output(plt)
if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else
@@ -98,6 +102,7 @@ function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
+163 -104
View File
@@ -1,6 +1,9 @@
# https://github.com/stevengj/PyPlot.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pyplot.jl"))
end
const _pyplot_attr = merge_with_base_supported([
:annotations,
@@ -16,7 +19,10 @@ const _pyplot_attr = merge_with_base_supported([
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z,
@@ -32,6 +38,10 @@ const _pyplot_attr = merge_with_base_supported([
:inset_subplots,
:dpi,
:colorbar_title,
:stride,
:framestyle,
:tick_direction,
:camera,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape,
@@ -121,6 +131,7 @@ end
# # anything else just gets a bluesred gradient
# py_colormap(c, α=nothing) = py_colormap(default_gradient(), α)
py_color(s) = py_color(parse(Colorant, string(s)))
py_color(c::Colorant) = (red(c), green(c), blue(c), alpha(c))
py_color(cs::AVec) = map(py_color, cs)
py_color(grad::ColorGradient) = py_color(grad.colors)
@@ -442,11 +453,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
@@ -491,24 +507,19 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
:zorder => plt.n,
:cmap => py_linecolormap(series),
:linewidth => py_dpi_scale(plt, series[:linewidth]),
:linestyle => py_linestyle(st, series[:linestyle])
:linestyle => py_linestyle(st, series[:linestyle]),
:norm => pycolors["Normalize"](; extrakw...)
)
clims = sp[:clims]
if is_2tuple(clims)
extrakw = KW()
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
kw[:norm] = pycolors["Normalize"](; extrakw...)
end
lz = collect(series[:line_z])
lz = _cycle(series[:line_z], 1:n)
handle = if is3d(st)
for rng in iter_segments(x, y, z)
length(rng) < 2 && continue
push!(segments, [(_cycle(x,i),_cycle(y,i),_cycle(z,i)) for i in rng])
for i in rng[1:end-1]
push!(segments, [(_cycle(x,i),_cycle(y,i),_cycle(z,i)),
(_cycle(x,i+1),_cycle(y,i+1),_cycle(z,i+1))])
end
end
# for i=1:n
# segments[i] = [(_cycle(x,i), _cycle(y,i), _cycle(z,i)), (_cycle(x,i+1), _cycle(y,i+1), _cycle(z,i+1))]
# end
lc = pyart3d["Line3DCollection"](segments; kw...)
lc[:set_array](lz)
ax[:add_collection3d](lc, zs=z) #, zdir='y')
@@ -516,18 +527,17 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
else
for rng in iter_segments(x, y)
length(rng) < 2 && continue
push!(segments, [(_cycle(x,i),_cycle(y,i)) for i in rng])
for i in rng[1:end-1]
push!(segments, [(_cycle(x,i),_cycle(y,i)), (_cycle(x,i+1),_cycle(y,i+1))])
end
end
# for i=1:n
# segments[i] = [(_cycle(x,i), _cycle(y,i)), (_cycle(x,i+1), _cycle(y,i+1))]
# end
lc = pycollections["LineCollection"](segments; kw...)
lc[:set_array](lz)
ax[:add_collection](lc)
lc
end
push!(handles, handle)
needs_colorbar = true
end
a = series[:arrow]
@@ -561,18 +571,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)
@@ -622,11 +625,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],
@@ -637,18 +635,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
@@ -686,11 +676,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))
@@ -698,13 +683,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...
@@ -721,14 +705,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)
@@ -746,7 +725,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
@@ -786,11 +764,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],
@@ -799,7 +772,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw...
)
push!(handles, handle)
needs_colorbar = true
end
if st == :shape
@@ -842,30 +814,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
@@ -963,23 +911,24 @@ 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] in (:zerolines, :grid) ? 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]),
labelcolor=py_color(a[:foreground_color_text]))
ax[axissym][:label][:set_color](py_color(a[:foreground_color_guide]))
colors=tickcolor,
labelcolor=py_color(a[:tickfontcolor]))
ax[axissym][:label][:set_color](py_color(a[:guidefontcolor]))
end
end
@@ -1033,12 +982,69 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
:title
end
ax[func][:set_text](sp[:title])
ax[func][:set_fontsize](py_dpi_scale(plt, sp[:titlefont].pointsize))
ax[func][:set_family](sp[:titlefont].family)
ax[func][:set_color](py_color(sp[:foreground_color_title]))
ax[func][:set_fontsize](py_dpi_scale(plt, sp[:titlefontsize]))
ax[func][:set_family](sp[:titlefontfamily])
ax[func][:set_color](py_color(sp[:titlefontcolor]))
# 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],size=py_dpi_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor]))
for lab in cb[:ax][:yaxis][:get_ticklabels]()
lab[:set_fontsize](py_dpi_scale(plt, sp[:yaxis][:tickfontsize]))
lab[:set_family](sp[:yaxis][:tickfontfamily])
lab[:set_color](py_color(sp[:yaxis][:tickfontcolor]))
end
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)
@@ -1053,19 +1059,28 @@ 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)
if ispolar(sp) && letter == :y
ax[:set_rlabel_position](90)
end
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")]()
end
pyaxis[:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefont].pointsize))
pyaxis[:label][:set_family](axis[:guidefont].family)
pyaxis[:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefontsize]))
pyaxis[:label][:set_family](axis[:guidefontfamily])
for lab in ax[Symbol("get_", letter, "ticklabels")]()
lab[:set_fontsize](py_dpi_scale(plt, axis[:tickfont].pointsize))
lab[:set_family](axis[:tickfont].family)
lab[:set_fontsize](py_dpi_scale(plt, axis[:tickfontsize]))
lab[:set_family](axis[:tickfontfamily])
lab[:set_rotation](axis[:rotation])
end
if axis[:grid]
if axis[:grid] && !(ticks in (:none, nothing, false))
fgcolor = py_color(axis[:foreground_color_grid])
pyaxis[:grid](true,
color = fgcolor,
@@ -1073,8 +1088,34 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
linewidth = axis[:gridlinewidth],
alpha = axis[:gridalpha])
ax[:set_axisbelow](true)
else
pyaxis[:grid](false)
end
py_set_axis_colors(ax, axis)
py_set_axis_colors(sp, ax, axis)
end
# showaxis
if !sp[:xaxis][:showaxis]
kw = KW()
for dir in (:top, :bottom)
if ispolar(sp)
ax[:spines]["polar"][:set_visible](false)
else
ax[:spines][string(dir)][:set_visible](false)
end
kw[dir] = kw[Symbol(:label,dir)] = "off"
end
ax[:xaxis][:set_tick_params](; which="both", kw...)
end
if !sp[:yaxis][:showaxis]
kw = KW()
for dir in (:left, :right)
if !ispolar(sp)
ax[:spines][string(dir)][:set_visible](false)
end
kw[dir] = kw[Symbol(:label,dir)] = "off"
end
ax[:yaxis][:set_tick_params](; which="both", kw...)
end
# aspect ratio
@@ -1083,11 +1124,19 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
ax[:set_aspect](isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C")
end
#camera/view angle
if is3d(sp)
#convert azimuthal to match GR behaviour
#view_init(elevation, azimuthal) so reverse :camera args
ax[:view_init]((sp[:camera].-(90,0))[end:-1:1]...)
end
# legend
py_add_legend(plt, sp, ax)
# this sets the bg color inside the grid
ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
end
py_drawfig(fig)
end
@@ -1177,10 +1226,19 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
for series in series_list(sp)
if should_add_to_legend(series)
# add a line/marker and a label
push!(handles, if series[:seriestype] == :shape
push!(handles, if series[:seriestype] == :shape || series[:fillrange] != nothing
pypatches[:Patch](
edgecolor = py_color(_cycle(series[:linecolor],1)),
facecolor = py_color(_cycle(series[:fillcolor],1)),
linewidth = py_dpi_scale(plt, clamp(series[:linewidth], 0, 5)),
)
elseif series[:seriestype] == :path
PyPlot.plt[:Line2D]((0,1),(0,0),
color = py_color(_cycle(series[:fillcolor],1)),
linewidth = py_dpi_scale(plt, 4)
linewidth = py_dpi_scale(plt, clamp(series[:linewidth], 0, 5)),
marker = py_marker(series[:markershape]),
markeredgecolor = py_markerstrokecolor(series),
markerfacecolor = py_markercolor(series)
)
else
series[:serieshandle][1]
@@ -1195,7 +1253,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
labels,
loc = get(_pyplot_legend_pos, leg, "best"),
scatterpoints = 1,
fontsize = py_dpi_scale(plt, sp[:legendfont].pointsize)
fontsize = py_dpi_scale(plt, sp[:legendfontsize])
# family = sp[:legendfont].family
# framealpha = 0.6
)
@@ -1203,8 +1261,9 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
fgcolor = py_color(sp[:foreground_color_legend])
lfcolor = py_color(sp[:legendfontcolor])
for txt in leg[:get_texts]()
PyPlot.plt[:setp](txt, color = fgcolor, family = sp[:legendfont].family)
PyPlot.plt[:setp](txt, color = lfcolor, family = sp[:legendfontfamily])
end
# set some legend properties
+4
View File
@@ -1,6 +1,10 @@
# https://github.com/Evizero/UnicodePlots.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
end
const _unicodeplots_attr = merge_with_base_supported([
:label,
:legend,
+3 -1
View File
@@ -2,7 +2,9 @@
# NOTE: backend should implement `html_body` and `html_head`
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
end
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
"""
+51 -24
View File
@@ -11,7 +11,7 @@ compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : ang
# -------------------------------------------------------------
immutable Shape
struct Shape
x::Vector{Float64}
y::Vector{Float64}
# function Shape(x::AVec, y::AVec)
@@ -22,6 +22,13 @@ immutable Shape
# end
# end
end
"""
Shape(x, y)
Shape(vertices)
Construct a polygon to be plotted
"""
Shape(verts::AVec) = Shape(unzip(verts)...)
Shape(s::Shape) = deepcopy(s)
@@ -32,6 +39,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
#deprecated
@deprecate shape_coords coords
"return the vertex points from a Shape or Segments object"
function coords(shape::Shape)
shape.x, shape.y
end
@@ -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)
@@ -235,7 +246,7 @@ end
# -----------------------------------------------------------------------
type Font
mutable struct Font
family::AbstractString
pointsize::Int
halign::Symbol
@@ -325,12 +336,17 @@ function scalefontsizes()
end
"Wrap a string with font info"
immutable PlotText
struct PlotText
str::AbstractString
font::Font
end
PlotText(str) = PlotText(string(str), font())
"""
text(string, args...)
Create a PlotText object wrapping a string with font info, for plot annotations
"""
text(t::PlotText) = t
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
@@ -343,13 +359,18 @@ Base.length(t::PlotText) = length(t.str)
# -----------------------------------------------------------------------
immutable Stroke
struct Stroke
width
color
alpha
style
end
"""
stroke(args...; alpha = nothing)
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing)
width = 1
color = :black
@@ -380,7 +401,7 @@ function stroke(args...; alpha = nothing)
end
immutable Brush
struct Brush
size # fillrange, markersize, or any other sizey attribute
color
alpha
@@ -413,7 +434,7 @@ end
# -----------------------------------------------------------------------
type SeriesAnnotations
mutable struct SeriesAnnotations
strs::AbstractVector # the labels/names
font::Font
baseshape::Nullable
@@ -492,7 +513,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
return
end
type EachAnn
mutable struct EachAnn
anns
x
y
@@ -517,12 +538,12 @@ annotations(sa::SeriesAnnotations) = sa
# -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)"
immutable ZValues
struct ZValues
values::Vector{Float64}
zrange::Tuple{Float64,Float64}
end
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values)))
function zvalues(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values))) where T<:Real
ZValues(collect(float(values)), map(Float64, zrange))
end
@@ -531,7 +552,7 @@ end
abstract type AbstractSurface end
"represents a contour or surface mesh"
immutable Surface{M<:AMat} <: AbstractSurface
struct Surface{M<:AMat} <: AbstractSurface
surf::M
end
@@ -543,7 +564,7 @@ for f in (:length, :size)
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
end
Base.copy(surf::Surface) = Surface(copy(surf.surf))
Base.eltype{T}(surf::Surface{T}) = eltype(T)
Base.eltype(surf::Surface{T}) where {T} = eltype(T)
function expand_extrema!(a::Axis, surf::Surface)
ex = a[:extrema]
@@ -554,7 +575,7 @@ function expand_extrema!(a::Axis, surf::Surface)
end
"For the case of representing a surface as a function of x/y... can possibly avoid allocations."
immutable SurfaceFunction <: AbstractSurface
struct SurfaceFunction <: AbstractSurface
f::Function
end
@@ -564,19 +585,19 @@ end
# # I don't want to clash with ValidatedNumerics, but this would be nice:
# ..(a::T, b::T) = (a,b)
immutable Volume{T}
struct Volume{T}
v::Array{T,3}
x_extents::Tuple{T,T}
y_extents::Tuple{T,T}
z_extents::Tuple{T,T}
end
default_extents{T}(::Type{T}) = (zero(T), one(T))
default_extents(::Type{T}) where {T} = (zero(T), one(T))
function Volume{T}(v::Array{T,3},
x_extents = default_extents(T),
y_extents = default_extents(T),
z_extents = default_extents(T))
function Volume(v::Array{T,3},
x_extents = default_extents(T),
y_extents = default_extents(T),
z_extents = default_extents(T)) where T
Volume(v, x_extents, y_extents, z_extents)
end
@@ -584,19 +605,25 @@ Base.Array(vol::Volume) = vol.v
for f in (:length, :size)
@eval Base.$f(vol::Volume, args...) = $f(vol.v, args...)
end
Base.copy{T}(vol::Volume{T}) = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
Base.eltype{T}(vol::Volume{T}) = T
Base.copy(vol::Volume{T}) where {T} = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
Base.eltype(vol::Volume{T}) where {T} = T
# -----------------------------------------------------------------------
# style is :open or :closed (for now)
immutable Arrow
struct Arrow
style::Symbol
side::Symbol # :head (default), :tail, or :both
headlength::Float64
headwidth::Float64
end
"""
arrow(args...)
Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
`side` (`:head`, `:tail` or `:both`), `headlength` and `headwidth`
"""
function arrow(args...)
style = :simple
side = :head
@@ -646,14 +673,14 @@ end
# -----------------------------------------------------------------------
"Represents data values with formatting that should apply to the tick labels."
immutable Formatted{T}
struct Formatted{T}
data::T
formatter::Function
end
# -----------------------------------------------------------------------
type BezierCurve{T <: FixedSizeArrays.Vec}
"create a BezierCurve for plotting"
mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T}
end
+4 -4
View File
@@ -558,7 +558,7 @@ function createGadflyAnnotationObject(x, y, txt::PlotText)
))
end
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
@@ -614,7 +614,7 @@ function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
@@ -677,7 +677,7 @@ setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# -------------------------------------------------------------------------
function doshow{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P})
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
@@ -692,7 +692,7 @@ getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.show{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P})
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
func = getGadflyWriteFunc($mime())
doshow(io, func, plt)
end
+1 -1
View File
@@ -2,7 +2,7 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes
immutable ShapeGeometry <: Gadfly.GeometryElement
struct ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol
+2 -2
View File
@@ -61,7 +61,7 @@ end
# ----------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
@@ -76,7 +76,7 @@ function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
+2 -2
View File
@@ -218,7 +218,7 @@ function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
marker[:attach](plt.o.widget)
end
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createQwtAnnotation(plt, ann...)
end
@@ -233,7 +233,7 @@ function getxy(plt::Plot{QwtBackend}, i::Int)
series.x, series.y
end
function setxy!{X,Y}(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.o.lines[i]
series.x, series.y = xy
plt
+1 -1
View File
@@ -217,7 +217,7 @@ function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::Abs
Winston.text(x, y, val)
end
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}})
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createWinstonAnnotationObject(plt, ann...)
end
+12 -12
View File
@@ -34,9 +34,9 @@ getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme{T<:Real}(s::Symbol, vals::AVec{T}; kw...) = ColorGradient(s, vals; kw...)
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme{T<:Colorant}(cs::AVec{T}; kw...) = ColorGradient(cs; kw...)
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
@@ -98,7 +98,7 @@ const _gradients = KW(
:lighttest => map(c -> lighten(c, 0.3), _testColors),
)
function register_gradient_colors{C<:Colorant}(name::Symbol, colors::AVec{C})
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
_gradients[name] = colors
end
@@ -109,11 +109,11 @@ default_gradient() = ColorGradient(:inferno)
# --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
immutable ColorGradient <: ColorScheme
struct ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient{S<:Real}(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
function ColorGradient(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing) where S<:Real
if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals))
end
@@ -138,7 +138,7 @@ Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
cs = _gradients[s]
if vals == 0:0
@@ -208,7 +208,7 @@ end
# --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant"
immutable ColorFunction <: ColorScheme
struct ColorFunction <: ColorScheme
f::Function
end
@@ -217,7 +217,7 @@ getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant"
immutable ColorZFunction <: ColorScheme
struct ColorZFunction <: ColorScheme
f::Function
end
@@ -226,7 +226,7 @@ getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
immutable ColorVector <: ColorScheme
struct ColorVector <: ColorScheme
v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end
@@ -238,7 +238,7 @@ getColorVector(scheme::ColorVector) = scheme.v
# --------------------------------------------------------------
"Wraps a single color"
immutable ColorWrapper <: ColorScheme
struct ColorWrapper <: ColorScheme
c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
end
@@ -347,8 +347,8 @@ function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numco
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette{C<:Colorant}(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
function get_color_palette(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
palette
end
+5 -5
View File
@@ -5,21 +5,21 @@
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
const FuncOrFuncs = @compat(Union{Function, AVec{Function}})
const FuncOrFuncs = Union{Function, AVec{Function}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
# missing
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
@@ -39,7 +39,7 @@ convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
+140 -58
View File
@@ -1,7 +1,7 @@
"""
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
"""
type PlotExample
mutable struct PlotExample
header::AbstractString
desc::AbstractString
exprs::Vector{Expr}
@@ -18,7 +18,14 @@ PlotExample("Lines",
),
PlotExample("Functions, adding data, and animations",
"Plot multiple functions. You can also put the function first, or use the form `plot(f, xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data: `x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with `push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the animation.",
"""
Plot multiple functions. You can also put the function first, or use the form `plot(f,
xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data:
`x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with
`push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available
to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the
animation.
""",
[:(begin
p = plot([sin,cos], zeros(0), leg=false)
anim = Animation()
@@ -37,23 +44,35 @@ PlotExample("Parametric plots",
),
PlotExample("Colors",
"Access predefined palettes (or build your own with the `colorscheme` method). Line/marker colors are auto-generated from the plot's palette, unless overridden. Set the `z` argument to turn on series gradients.",
"""
Access predefined palettes (or build your own with the `colorscheme` method).
Line/marker colors are auto-generated from the plot's palette, unless overridden. Set
the `z` argument to turn on series gradients.
""",
[:(begin
y = rand(100)
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=0, α=0.6)
scatter!(y, zcolor=abs.(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y-0.5)+4, lab="grad")
y = rand(100)
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=0, α=0.6)
scatter!(y, zcolor=abs.(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y-0.5)+4,
lab="grad")
end)]
),
PlotExample("Global",
"Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow you to pass a tuple or value which will be mapped to the relevant args automatically. The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`, `yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`",
"""
Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow
you to pass a tuple or value which will be mapped to the relevant args automatically.
The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during
the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`,
`yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`
""",
[:(begin
y = rand(20,3)
plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2), leg=false)
hline!(mean(y,1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
vline!([5,10])
title!("TITLE")
yaxis!("YLABEL", :log10)
y = rand(20,3)
plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2),
leg=false)
hline!(mean(y,1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
vline!([5,10])
title!("TITLE")
yaxis!("YLABEL", :log10)
end)]
),
@@ -73,7 +92,14 @@ PlotExample("Images",
),
PlotExample("Arguments",
"Plot multiple series with different numbers of points. Mix arguments that apply to all series (marker/markersize) with arguments unique to each series (colors). Special arguments `line`, `marker`, and `fill` will automatically figure out what arguments to set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with `line`.) Note that we pass a matrix of colors, and this applies the colors to each series.",
"""
Plot multiple series with different numbers of points. Mix arguments that apply to all
series (marker/markersize) with arguments unique to each series (colors). Special
arguments `line`, `marker`, and `fill` will automatically figure out what arguments to
set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with
`line`.) Note that we pass a matrix of colors, and this applies the colors to each
series.
""",
[:(begin
ys = Vector[rand(10), rand(20)]
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,stroke(3,:gray)))
@@ -115,12 +141,13 @@ PlotExample("Line types",
PlotExample("Line styles",
"",
[:(begin
styles = filter(s -> s in Plots.supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20,n),1)
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
styles = filter(s -> s in Plots.supported_styles(),
[:solid, :dash, :dot, :dashdot, :dashdotdot])
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20,n),1)
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
),
PlotExample("Marker types",
@@ -145,24 +172,30 @@ PlotExample("Bar",
PlotExample("Histogram",
"",
[:(begin
histogram(randn(1000), nbins=20)
histogram(randn(1000), bins = :scott, weights = repeat(1:5, outer = 200))
end)]
),
PlotExample("Subplots",
"""
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate arbitrarily complex subplot layouts.
""",
"""
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate
arbitrarily complex subplot layouts.
""",
[:(begin
l = @layout([a{0.1h}; b [c;d e]])
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=false)
l = @layout([a{0.1h}; b [c;d e]])
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false,
ticks=nothing, border=:none)
end)]
),
PlotExample("Adding to subplots",
"Note here the automatic grid layout, as well as the order in which new series are added to the plots.",
"""
Note here the automatic grid layout, as well as the order in which new series are added
to the plots.
""",
[:(begin
plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black])
plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbow],
bg_inside=[:orange :pink :darkblue :black])
end)]
),
@@ -175,43 +208,63 @@ PlotExample("",
),
PlotExample("Open/High/Low/Close",
"Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y` argument. This uses recipes to first convert the tuples to OHLC objects, and subsequently create a :path series with the appropriate line segments.",
"""
Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y`
argument. This uses recipes to first convert the tuples to OHLC objects, and
subsequently create a :path series with the appropriate line segments.
""",
[:(begin
n=20
hgt=rand(n)+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
y = OHLC[(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i], closepct[i]*hgt[i]+bot[i]) for i in 1:n]
ohlc(y)
n=20
hgt=rand(n)+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
y = OHLC[(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i],
closepct[i]*hgt[i]+bot[i]) for i in 1:n]
ohlc(y)
end)]
),
PlotExample("Annotations",
"The `annotations` keyword is used for text annotations in data-coordinates. Pass in a tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(; annotation=ann)`. Series annotations are used for annotating individual data points. They require only the annotation... x/y values are computed. A `PlotText` object can be build with the method `text(string, attr...)`, which wraps font and color attributes.",
"""
The `annotations` keyword is used for text annotations in data-coordinates. Pass in a
tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(;
annotation=ann)`. Series annotations are used for annotating individual data points.
They require only the annotation... x/y values are computed. A `PlotText` object can be
build with the method `text(string, attr...)`, which wraps font and color attributes.
""",
[:(begin
y = rand(10)
plot(y, annotations = (3,y[3],text("this is #3",:left)), leg=false)
annotate!([(5, y[5], text("this is #5",16,:red,:center)), (10, y[10], text("this is #10",:right,20,"courier"))])
scatter!(linspace(2,8,6), rand(6), marker=(50,0.2,:orange), series_annotations = ["series","annotations","map","to","series",text("data",:green)])
y = rand(10)
plot(y, annotations = (3,y[3],text("this is #3",:left)), leg=false)
annotate!([(5, y[5], text("this is #5",16,:red,:center)),
(10, y[10], text("this is #10",:right,20,"courier"))])
scatter!(linspace(2,8,6), rand(6), marker=(50,0.2,:orange),
series_annotations = ["series","annotations","map","to","series",
text("data",:green)])
end)]
),
PlotExample("Custom Markers",
"A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and the size is expected to be rougly the area of the unit circle.",
"""A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported
backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and
the size is expected to be rougly the area of the unit circle.
""",
[:(begin
verts = [(-1.0,1.0),(-1.28,0.6),(-0.2,-1.4),(0.2,-1.4),(1.28,0.6),(1.0,1.0),
(-1.0,1.0),(-0.2,-0.6),(0.0,-0.2),(-0.4,0.6),(1.28,0.6),(0.2,-1.4),
(-0.2,-1.4),(0.6,0.2),(-0.2,0.2),(0.0,-0.2),(0.2,0.2),(-0.2,-0.6)]
x = 0.1:0.2:0.9
y = 0.7rand(5)+0.15
plot(x, y, line = (3,:dash,:lightblue), marker = (Shape(verts),30,RGBA(0,0,0,0.2)),
bg=:pink, fg=:darkblue, xlim = (0,1), ylim=(0,1), leg=false)
verts = [(-1.0,1.0),(-1.28,0.6),(-0.2,-1.4),(0.2,-1.4),(1.28,0.6),(1.0,1.0),
(-1.0,1.0),(-0.2,-0.6),(0.0,-0.2),(-0.4,0.6),(1.28,0.6),(0.2,-1.4),
(-0.2,-1.4),(0.6,0.2),(-0.2,0.2),(0.0,-0.2),(0.2,0.2),(-0.2,-0.6)]
x = 0.1:0.2:0.9
y = 0.7rand(5)+0.15
plot(x, y, line = (3,:dash,:lightblue), marker = (Shape(verts),30,RGBA(0,0,0,0.2)),
bg=:pink, fg=:darkblue, xlim = (0,1), ylim=(0,1), leg=false)
end)]
),
PlotExample("Contours",
"Any value for fill works here. We first build a filled contour from a function, then an unfilled contour from a matrix.",
"""
Any value for fill works here. We first build a filled contour from a function, then an
unfilled contour from a matrix.
""",
[:(begin
x = 1:0.5:20
y = 1:0.5:10
@@ -252,7 +305,7 @@ PlotExample("DataFrames",
[:(begin
import RDatasets
iris = RDatasets.dataset("datasets", "iris")
scatter(iris, :SepalLength, :SepalWidth, group=:Species,
@df iris scatter(:SepalLength, :SepalWidth, group=:Species,
title = "My awesome plot", xlabel = "Length", ylabel = "Width",
marker = (0.5, [:cross :hex :star7], 12), bg=RGB(.2,.2,.2))
end)]
@@ -262,7 +315,8 @@ PlotExample("Groups and Subplots",
"",
[:(begin
group = rand(map(i->"group $i",1:4),100)
plot(rand(100), layout=@layout([a b;c]), group=group, linetype=[:bar :scatter :steppre])
plot(rand(100), layout=@layout([a b;c]), group=group,
linetype=[:bar :scatter :steppre], linecolor = :match)
end)]
),
@@ -288,9 +342,10 @@ PlotExample("Heatmap, categorical axes, and aspect_ratio",
PlotExample("Layouts, margins, label rotation, title location",
"",
[:(begin
using Plots.PlotMeasures # for Measures, e.g. mm and px
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
title_location=:left, left_margin=[20mm 0mm],
bottom_margin=50px, xrotation=60)
bottom_margin=10px, xrotation=60)
end)]
),
@@ -299,8 +354,8 @@ PlotExample("Boxplot and Violin series recipes",
[:(begin
import RDatasets
singers = RDatasets.dataset("lattice", "singer")
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue))
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
@df singers violin(:VoicePart, :Height, line = 0, fill = (0.2, :blue))
@df singers boxplot!(:VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
end)]
),
@@ -321,16 +376,22 @@ PlotExample("Animation with subplots",
),
PlotExample("Spy",
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`.",
"""
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
various different nonzero values, a colorbar is added. The colorbar can be disabled with
`legend = nothing`.
""",
[:(begin
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
plot(spy(a, markershape = :dtriangle), spy(b), markersize = 3, title = ["Unique nonzeros" "Different nonzeros"])
plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"])
end)]
),
PlotExample("Magic grid argument",
"The grid lines can be modified individually for each axis with the magic grid argument.",
"""
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")
@@ -341,6 +402,20 @@ PlotExample("Magic grid argument",
end)]
),
PlotExample("Framestyle",
"""
The style of the frame/axes of a (sub)plot can be changed with the `framestyle`
attribute. The default framestyle is `:axes`.
""",
[:(begin
scatter(fill(randn(10), 6), fill(randn(10), 6),
framestyle = [:box :semi :origin :zerolines :grid :none],
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
color = RowVector(1:6), layout = 6, label = "", markerstrokewidth = 0,
ticks = -2:2)
end)]
),
]
# ---------------------------------------------------------------------------------
@@ -360,6 +435,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
+19 -11
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
@@ -17,7 +13,7 @@ Base.zero(::Type{typeof(mm)}) = 0mm
Base.one(::Type{typeof(mm)}) = 1mm
Base.typemin(::typeof(mm)) = -Inf*mm
Base.typemax(::typeof(mm)) = Inf*mm
Base.convert{F<:AbstractFloat}(::Type{F}, l::AbsoluteLength) = convert(F, l.value)
Base.convert(::Type{F}, l::AbsoluteLength) where {F<:AbstractFloat} = convert(F, l.value)
# TODO: these are unintuitive and may cause tricky bugs
# Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
@@ -99,7 +95,7 @@ end
# -----------------------------------------------------------
# points combined by x/y, pct, and length
type MixedMeasures
mutable struct MixedMeasures
xy::Float64
pct::Float64
len::AbsoluteLength
@@ -133,7 +129,12 @@ make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h
make_measure_vert(m::Measure) = m
"""
bbox(x, y, w, h [,originargs...])
bbox(layout)
Create a bounding box for plotting
"""
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
oargs = vcat(oarg1, originargs...)
orighor = :left
@@ -215,7 +216,7 @@ bottompad(layout::AbstractLayout) = 0mm
# RootLayout
# this is the parent of the top-level layout
immutable RootLayout <: AbstractLayout end
struct RootLayout <: AbstractLayout end
Base.parent(::RootLayout) = nothing
parent_bbox(::RootLayout) = defaultbox
@@ -225,7 +226,7 @@ bbox(::RootLayout) = defaultbox
# EmptyLayout
# contains blank space
type EmptyLayout <: AbstractLayout
mutable struct EmptyLayout <: AbstractLayout
parent::AbstractLayout
bbox::BoundingBox
attr::KW # store label, width, and height for initialization
@@ -243,7 +244,7 @@ _update_min_padding!(layout::EmptyLayout) = nothing
# GridLayout
# nested, gridded layout with optional size percentages
type GridLayout <: AbstractLayout
mutable struct GridLayout <: AbstractLayout
parent::AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox
@@ -253,6 +254,13 @@ type GridLayout <: AbstractLayout
attr::KW
end
"""
grid(args...; kw...)
Create a grid layout for subplots. `args` specify the dimensions, e.g.
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two
columns of different width.
"""
grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout(dims...;
@@ -473,12 +481,12 @@ function layout_args(n::Integer)
GridLayout(nr, nc), n
end
function layout_args{I<:Integer}(sztup::NTuple{2,I})
function layout_args(sztup::NTuple{2,I}) where I<:Integer
nr, nc = sztup
GridLayout(nr, nc), nr*nc
end
function layout_args{I<:Integer}(sztup::NTuple{3,I})
function layout_args(sztup::NTuple{3,I}) where I<:Integer
n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n
+17 -5
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
@@ -182,7 +193,7 @@ function Base.show(io::IO, ::MIME"text/html", plt::Plot)
end
end
function _show{B}(io::IO, m, plt::Plot{B})
function _show(io::IO, m, plt::Plot{B}) where B
# Base.show_backtrace(STDOUT, backtrace())
warn("_show is not defined for this backend. m=", string(m))
end
@@ -192,12 +203,13 @@ end
# for writing to io streams... first prepare, then callback
for mime in keys(_mimeformats)
@eval function Base.show{B}(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B})
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B}) where B
prepare_output(plt)
_show(io, m, plt)
end
end
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
@@ -246,7 +258,6 @@ end
const _ijulia_output = String["text/html"]
using Requires
@require IJulia begin
if IJulia.inited
export set_ijulia_output
@@ -266,6 +277,7 @@ using Requires
show(io, MIME("text/html"), plt)
end
ENV["MPLBACKEND"] = "Agg"
set_ijulia_output("text/html")
end
end
@@ -280,7 +292,7 @@ end
Media.media(Plot, Media.Plot)
_show{B}(io::IO, m::MIME"text/plain", plt::Plot{B}) = print(io, "Plot{$B}()")
_show(io::IO, m::MIME"text/plain", plt::Plot{B}) where {B} = print(io, "Plot{$B}()")
function Juno.render(e::Juno.Editor, plt::Plot)
Juno.render(e, nothing)
+8 -3
View File
@@ -210,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)
@@ -264,7 +264,7 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# extract subplot/axis attributes from kw and add to sp_attr
attr = KW()
for (k,v) in kw
for (k,v) in collect(kw)
if haskey(_subplot_defaults, k) || haskey(_axis_defaults_byletter, k)
attr[k] = pop!(kw, k)
end
@@ -301,7 +301,7 @@ end
# getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes
function _prepare_subplot{T}(plt::Plot{T}, d::KW)
function _prepare_subplot(plt::Plot{T}, d::KW) where T
st::Symbol = d[:seriestype]
sp::Subplot{T} = d[:subplot]
sp_idx = get_subplot_index(plt, sp)
@@ -364,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)
+10 -4
View File
@@ -1,11 +1,15 @@
type CurrentPlot
mutable struct CurrentPlot
nullableplot::Nullable{AbstractPlot}
end
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")
@@ -29,7 +33,7 @@ convertSeriesIndex(plt::Plot, n::Int) = n
"""
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
```
plot(args...; kw...) # creates a new plot window, and sets it to be the current
@@ -38,7 +42,9 @@ The main plot command. Use `plot` to create a new plot object, and `plot!` to a
```
There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected.
When you pass in matrices, it splits by columns. See the documentation for more info.
When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr([attr])`
function, where `attr` is the symbol `:Series:`, `:Subplot:`, `:Plot` or `:Axis`. Pass any attribute to `plotattr`
as a String to look up its docstring; e.g. `plotattr("seriestype")`.
"""
# this creates a new plot with args/kw and sets it to be the current plot
@@ -80,7 +86,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
+110 -84
View File
@@ -47,7 +47,7 @@ end
num_series(x::AMat) = size(x,2)
num_series(x) = 1
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::AbstractPlot) = throw(MethodError("Unmatched plot recipe: $T"))
RecipesBase.apply_recipe(d::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
@@ -79,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)
@@ -102,6 +102,25 @@ end
end
@deps vline path
# ---------------------------------------------------------------------------
# path and scatter
# create a path from steps
@recipe function f(::Type{Val{:scatterpath}}, x, y, z)
x := x
y := y
seriestype := :scatter
@series begin
seriestype := :path
label := ""
primary := false
()
end
()
end
@deps scatterpath path scatter
# ---------------------------------------------------------------------------
# steps
@@ -123,11 +142,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 +163,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 +189,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 +210,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 +243,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 +293,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 +306,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 +339,7 @@ end
expand_extrema!(axis, widen(ignorenan_extrema(xseg.pts)...))
# switch back
if !isvertical(d)
if !isvertical(plotattributes)
xseg, yseg = yseg, xseg
end
@@ -343,9 +362,9 @@ _bin_centers(v::AVec) = (v[1:end-1] + v[2:end]) / 2
_is_positive(x) = (x > 0) && !(x 0)
_positive_else_nan{T}(::Type{T}, x::Real) = _is_positive(x) ? T(x) : T(NaN)
_positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN)
function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector, scale::Symbol)
function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) where T<:AbstractFloat
if scale in _logScales
[_positive_else_nan(T, x) for x in V]
else
@@ -354,7 +373,7 @@ function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector,
end
function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real
if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
else
@@ -363,7 +382,7 @@ function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
end
function _preprocess_binbarlike_weights{T<:AbstractFloat}(::Type{T}, w, wscale::Symbol)
function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:AbstractFloat
w_adj = _scale_adjusted_values(T, w, wscale)
w_min = ignorenan_minimum(w_adj)
w_max = ignorenan_maximum(w_adj)
@@ -389,8 +408,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 +421,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 +484,17 @@ end
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
axis = d[:subplot][Plots.isvertical(d) ? :xaxis : :yaxis]
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(d)
if !isvertical(plotattributes)
xpts, ypts = ypts, xpts
end
# create a secondary series for the markers
if d[:markershape] != :none
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := _bin_centers(edge)
@@ -497,66 +516,73 @@ end
end
Plots.@deps stepbins path
wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto)
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
_iqr(v) = quantile(v, 0.75) - quantile(v, 0.25)
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
n_samples = length(linearindices(first(vs)))
# Estimator for number of samples in one row/column of bins along each axis:
n = max(1, n_samples^(1/N))
# 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)
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) = binning
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} = StatsBase.histrange(vs[dim], binning, :left)
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
_hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) =
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...))
_hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) =
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
map(dim -> _hist_edge(vs, dim, binning), (1:N...))
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
function _make_hist{N}(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing)
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
edges = _hist_edges(vs, binning)
h = float( weights == nothing ?
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, vs, weights, edges, closed = :left)
StatsBase.fit(StatsBase.Histogram, vs, StatsBase.Weights(weights), edges, closed = :left)
)
normalize!(h, mode = _hist_norm_mode(normed))
end
@recipe function f(::Type{Val{:histogram}}, x, y, z)
seriestype := :barhist
seriestype := length(y) > 1e6 ? :stephist : :barhist
()
end
@deps histogram barhist
@recipe function f(::Type{Val{:barhist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :barbins
@@ -565,7 +591,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 +600,7 @@ end
@deps stephist stepbins
@recipe function f(::Type{Val{:scatterhist}}, x, y, z)
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.weights
seriestype := :scatterbins
@@ -583,18 +609,18 @@ end
@deps scatterhist scatterbins
@recipe function f{T, E}(h::StatsBase.Histogram{T, 1, E})
@recipe function f(h::StatsBase.Histogram{T, 1, E}) where {T, E}
seriestype --> :barbins
st_map = Dict(
:bar => :barbins, :scatter => :scatterbins, :step => :stepbins,
:steppost => :stepbins # :step can be mapped to :steppost in pre-processing
)
seriestype := get(st_map, d[:seriestype], d[:seriestype])
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
if d[:seriestype] == :scatterbins
if plotattributes[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, h.edges[1], h.weights)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, h.edges[1], h.weights)
xerror --> diff(h.edges[1])/2
seriestype := :scatter
(Plots._bin_centers(edge), weights)
@@ -604,7 +630,7 @@ end
end
@recipe function f{H <: StatsBase.Histogram}(hv::AbstractVector{H})
@recipe function f(hv::AbstractVector{H}) where H <: StatsBase.Histogram
for h in hv
@series begin
h
@@ -641,7 +667,7 @@ Plots.@deps bins2d heatmap
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
h = _make_hist((x, y), d[:bins], normed = d[:normalize], weights = d[:weights])
h = _make_hist((x, y), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
x := h.edges[1]
y := h.edges[2]
z := Surface(h.weights)
@@ -651,7 +677,7 @@ end
@deps histogram2d bins2d
@recipe function f{T, E}(h::StatsBase.Histogram{T, 2, E})
@recipe function f(h::StatsBase.Histogram{T, 2, E}) where {T, E}
seriestype --> :bins2d
(h.edges[1], h.edges[2], Surface(h.weights))
end
@@ -662,7 +688,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 +751,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 +860,9 @@ end
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
@recipe function f(::Type{Val{:quiver}}, x, y, z)
if :arrow in supported_attrs()
quiver_using_arrows(d)
quiver_using_arrows(plotattributes)
else
quiver_using_hack(d)
quiver_using_hack(plotattributes)
end
()
end
@@ -847,7 +873,8 @@ end
# TODO: move OHLC to PlotRecipes finance.jl
type OHLC{T<:Real}
"Represent Open High Low Close data (used in finance)"
mutable struct OHLC{T<:Real}
open::T
high::T
low::T
@@ -886,10 +913,10 @@ end
# to squash ambiguity warnings...
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) = error()
@recipe f(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error()
# this must be OHLC?
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) = x, OHLC[OHLC(t...) for t in ohlc]
@recipe f(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc]
@recipe function f(x::AVec, v::AVec{OHLC})
seriestype := :path
@@ -929,6 +956,7 @@ end
mat = g.args[1]
if length(unique(mat[mat .!= 0])) < 2
legend --> nothing
seriescolor --> cgrad([invisible(), fg_color(plotattributes)])
end
n,m = size(mat)
Plots.SliceIt, 1:m, 1:n, Surface(mat)
@@ -937,23 +965,21 @@ end
@recipe function f(::Type{Val{:spy}}, x,y,z)
yflip := true
aspect_ratio := 1
rs, cs, zs = findnz(z.surf)
xlim := ignorenan_extrema(cs)
ylim := ignorenan_extrema(rs)
if d[:markershape] == :none
markershape := :circle
newz = fill(NaN, size(z)...)
for i in eachindex(zs)
newz[rs[i],cs[i]] = zs[i]
end
if d[:markersize] == default(:markersize)
markersize := 1
end
markerstrokewidth := 0
marker_z := zs
label := ""
x := cs
y := rs
z := nothing
seriestype := :scatter
seriestype := :heatmap
grid --> false
framestyle --> :box
x := x
y := y
z := Surface(newz)
()
end
@@ -979,7 +1005,7 @@ datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
# -------------------------------------------------
# Complex Numbers
@recipe function f{T<:Number}(A::Array{Complex{T}})
@recipe function f(A::Array{Complex{T}}) where T<:Number
xguide --> "Re(x)"
yguide --> "Im(x)"
real.(A), imag.(A)
@@ -988,7 +1014,7 @@ end
# Splits a complex matrix to its real and complex parts
# Reals defaults solid, imaginary defaults dashed
# Label defaults are changed to match the real-imaginary reference / indexing
@recipe function f{T<:Real,T2}(x::AbstractArray{T},y::Array{Complex{T2}})
@recipe function f(x::AbstractArray{T},y::Array{Complex{T2}}) where {T<:Real,T2}
ylabel --> "Re(y)"
zlabel --> "Im(y)"
x,real.(y),imag.(y)
+137 -62
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
@@ -17,10 +20,10 @@ convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector{T<:AbstractString}(v::AVec{T}, d::KW) = Any[v], nothing
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
@@ -96,8 +99,8 @@ nobigs(v) = v
end
# not allowed
compute_xyz{F<:Function}(x::Void, y::FuncOrFuncs{F}, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz{F<:Function}(x::Void, y::Void, z::FuncOrFuncs{F}) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
@@ -106,7 +109,7 @@ compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# we are going to build recipes to do the processing and splitting of the args
# ensure we dispatch to the slicer
immutable SliceIt end
struct SliceIt end
# the catch-all recipes
@recipe function f(::Type{SliceIt}, x, y, z)
@@ -125,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)
@@ -160,10 +163,10 @@ immutable SliceIt end
end
# this is the default "type recipe"... just pass the object through
@recipe f{T<:Any}(::Type{T}, v::T) = v
@recipe f(::Type{T}, v::T) where {T<:Any} = v
# this should catch unhandled "series recipes" and error with a nice message
@recipe f{V<:Val}(::Type{V}, x, y, z) = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
@recipe f(::Type{V}, x, y, z) where {V<:Val} = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
@@ -171,6 +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
@@ -197,16 +201,16 @@ end
# end
# don't do anything for ints or floats
_apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
_apply_type_recipe(d, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
# handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z)
did_replace = false
newx = _apply_type_recipe(d, x)
newx = _apply_type_recipe(plotattributes, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
newy = _apply_type_recipe(plotattributes, y)
y === newy || (did_replace = true)
newz = _apply_type_recipe(d, z)
newz = _apply_type_recipe(plotattributes, z)
z === newz || (did_replace = true)
if did_replace
newx, newy, newz
@@ -216,9 +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)
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat}
if all3D(plotattributes)
n,m = size(mat)
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Surface(mat)
else
SliceIt, nothing, mat, nothing
@@ -281,11 +285,11 @@ end
end
# if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface
@recipe function f{T<:AbstractMatrix}(fmt::Formatted{T})
if all3D(d)
@recipe function f(fmt::Formatted{T}) where T<:AbstractMatrix
if all3D(plotattributes)
mat = fmt.data
n,m = size(mat)
wrap_surfaces(d)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
else
SliceIt, nothing, fmt, nothing
@@ -293,7 +297,7 @@ end
end
# assume this is a Volume, so construct one
@recipe function f{T<:Number}(vol::AbstractArray{T,3}, args...)
@recipe function f(vol::AbstractArray{T,3}, args...) where T<:Number
seriestype := :volume
SliceIt, nothing, Volume(vol, args...), nothing
end
@@ -301,10 +305,10 @@ end
# # images - grays
@recipe function f{T<:Gray}(mat::AMat{T})
@recipe function f(mat::AMat{T}) where T<:Gray
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
n, m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
@@ -316,7 +320,7 @@ end
# # images - colors
@recipe function f{T<:Colorant}(mat::AMat{T})
@recipe function f(mat::AMat{T}) where T<:Colorant
n, m = size(mat)
if is_seriestype_supported(:image)
@@ -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
@@ -354,16 +358,36 @@ end
# function without range... use the current range of the x-axis
@recipe function f{F<:Function}(f::FuncOrFuncs{F})
plt = d[:plot_object]
@recipe function f(f::FuncOrFuncs{F}) where F<:Function
plt = plotattributes[:plot_object]
xmin, xmax = try
axis_limits(plt[1][:xaxis])
catch
-5, 5
xm = tryrange(f, [-5,-1,0,0.01])
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
end
f, xmin, xmax
end
# try some intervals over which the function may be defined
function tryrange(F::AbstractArray, vec)
rets = [tryrange(f, vec) for f in F] # get the preferred for each
maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all)
rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there
rets[1]
end
function tryrange(F, vec)
for v in vec
try
tmp = F(v)
return v
catch
end
end
error("$F is not a Function, or is not defined at any of the values $vec")
end
#
# # --------------------------------------------------------------------
# # 2 arguments
@@ -373,7 +397,7 @@ end
# # if functions come first, just swap the order (not to be confused with parametric functions...
# # as there would be more than one function passed in)
@recipe function f{F<:Function}(f::FuncOrFuncs{F}, x)
@recipe function f(f::FuncOrFuncs{F}, x) where F<:Function
F2 = typeof(x)
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
x, f
@@ -404,7 +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
@@ -441,19 +465,19 @@ end
xs = adapted_grid(f, (xmin, xmax))
xs, f
end
@recipe function f{F<:Function}(fs::AbstractArray{F}, xmin::Number, xmax::Number)
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
xs, fs
end
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, linspace(umin, umax, n)
#
# # special handling... 3D parametric function(s)
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
end
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
fx, fy, fz, linspace(umin, umax, numPoints)
end
@@ -468,28 +492,28 @@ end
#
# # (x,y) tuples
@recipe f{R1<:Number,R2<:Number}(xy::AVec{Tuple{R1,R2}}) = unzip(xy)
@recipe f{R1<:Number,R2<:Number}(xy::Tuple{R1,R2}) = [xy[1]], [xy[2]]
@recipe f(xy::AVec{Tuple{R1,R2}}) where {R1<:Number,R2<:Number} = unzip(xy)
@recipe f(xy::Tuple{R1,R2}) where {R1<:Number,R2<:Number} = [xy[1]], [xy[2]]
#
# # (x,y,z) tuples
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::AVec{Tuple{R1,R2,R3}}) = unzip(xyz)
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]]
@recipe f(xyz::AVec{Tuple{R1,R2,R3}}) where {R1<:Number,R2<:Number,R3<:Number} = unzip(xyz)
@recipe f(xyz::Tuple{R1,R2,R3}) where {R1<:Number,R2<:Number,R3<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(d,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
@recipe f(xyuv::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f(xyuv::Tuple{R1,R2,R3,R4}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
#
# # 2D FixedSizeArrays
@recipe f{T<:Number}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = unzip(xy)
@recipe f{T<:Number}(xy::FixedSizeArrays.Vec{2,T}) = [xy[1]], [xy[2]]
@recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
@recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
#
# # 3D FixedSizeArrays
@recipe f{T<:Number}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = unzip(xyz)
@recipe f{T<:Number}(xyz::FixedSizeArrays.Vec{3,T}) = [xyz[1]], [xyz[2]], [xyz[3]]
@recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
@recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
#
# # --------------------------------------------------------------------
@@ -509,13 +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
+6 -1
View File
@@ -1,6 +1,6 @@
function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend
Subplot{T}(
parent,
Series[],
@@ -13,6 +13,11 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
)
end
"""
plotarea(subplot)
Return the bounding box of a subplot
"""
plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
+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
+8 -8
View File
@@ -6,20 +6,20 @@ const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
immutable PlotsDisplay <: Display end
struct PlotsDisplay <: Display end
# -----------------------------------------------------------
immutable InputWrapper{T}
struct InputWrapper{T}
obj::T
end
wrap{T}(obj::T) = InputWrapper{T}(obj)
wrap(obj::T) where {T} = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
type Series
mutable struct Series
d::KW
end
@@ -29,7 +29,7 @@ attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
# -----------------------------------------------------------
# a single subplot
type Subplot{T<:AbstractBackend} <: AbstractLayout
mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
parent::AbstractLayout
series_list::Vector{Series} # arguments for each series
minpad::Tuple # leftpad, toppad, rightpad, bottompad
@@ -45,12 +45,12 @@ Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
# -----------------------------------------------------------
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
type Axis
mutable struct Axis
sps::Vector{Subplot}
d::KW
end
type Extrema
mutable struct Extrema
emin::Float64
emax::Float64
end
@@ -63,7 +63,7 @@ const SubplotMap = Dict{Any, Subplot}
# -----------------------------------------------------------
type Plot{T<:AbstractBackend} <: AbstractPlot{T}
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type
n::Int # number of series
attr::KW # arguments for the whole plot
+206 -49
View File
@@ -114,7 +114,7 @@ function regressionXY(x, y)
regx, regy
end
function replace_image_with_heatmap{T<:Colorant}(z::Array{T})
function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
@show T, size(z)
n, m = size(z)
# idx = 0
@@ -137,15 +137,15 @@ function imageHack(d::KW)
end
# ---------------------------------------------------------------
type Segments{T}
"Build line segments for plotting"
mutable struct Segments{T}
pts::Vector{T}
end
# Segments() = Segments{Float64}(zeros(0))
Segments() = Segments(Float64)
Segments{T}(::Type{T}) = Segments(T[])
Segments(::Type{T}) where {T} = Segments(T[])
Segments(p::Int) = Segments(NTuple{2,Float64}[])
@@ -157,7 +157,7 @@ to_nan(::Type{NTuple{2,Float64}}) = (NaN, NaN)
coords(segs::Segments{Float64}) = segs.pts
coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts]
function Base.push!{T}(segments::Segments{T}, vs...)
function Base.push!(segments::Segments{T}, vs...) where T
if !isempty(segments.pts)
push!(segments.pts, to_nan(T))
end
@@ -167,7 +167,7 @@ function Base.push!{T}(segments::Segments{T}, vs...)
segments
end
function Base.push!{T}(segments::Segments{T}, vs::AVec)
function Base.push!(segments::Segments{T}, vs::AVec) where T
if !isempty(segments.pts)
push!(segments.pts, to_nan(T))
end
@@ -181,10 +181,11 @@ end
# -----------------------------------------------------
# helper to manage NaN-separated segments
type SegmentsIterator
mutable struct SegmentsIterator
args::Tuple
n::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
@@ -231,8 +232,8 @@ end
# Find minimal type that can contain NaN and x
# To allow use of NaN separated segments with categorical x axis
float_extended_type{T}(x::AbstractArray{T}) = Union{T,Float64}
float_extended_type{T<:Real}(x::AbstractArray{T}) = Float64
float_extended_type(x::AbstractArray{T}) where {T} = Union{T,Float64}
float_extended_type(x::AbstractArray{T}) where {T<:Real} = Float64
# ------------------------------------------------------------------------------------
@@ -258,27 +259,27 @@ _cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
makevec(v::AVec) = v
makevec{T}(v::T) = T[v]
makevec(v::T) where {T} = T[v]
"duplicate a single value, or pass the 2-tuple through"
maketuple(x::Real) = (x,x)
maketuple{T,S}(x::Tuple{T,S}) = x
maketuple(x::Tuple{T,S}) where {T,S} = x
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
mapFuncOrFuncs{F<:Function}(fs::AVec{F}, u::AVec) = [map(f, u) for f in fs]
mapFuncOrFuncs(fs::AVec{F}, u::AVec) where {F<:Function} = [map(f, u) for f in fs]
unzip{X,Y}(xy::AVec{Tuple{X,Y}}) = [t[1] for t in xy], [t[2] for t in xy]
unzip{X,Y,Z}(xyz::AVec{Tuple{X,Y,Z}}) = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip{X,Y,U,V}(xyuv::AVec{Tuple{X,Y,U,V}}) = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2] for t in xy]
unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip{T}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = T[t[1] for t in xy], T[t[2] for t in xy]
unzip{T}(xy::FixedSizeArrays.Vec{2,T}) = T[xy[1]], T[xy[2]]
unzip(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
unzip(xy::FixedSizeArrays.Vec{2,T}) where {T} = T[xy[1]], T[xy[2]]
unzip{T}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip{T}(xyz::FixedSizeArrays.Vec{3,T}) = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip(xyz::FixedSizeArrays.Vec{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip{T}(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip{T}(xyuv::FixedSizeArrays.Vec{4,T}) = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
unzip(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip(xyuv::FixedSizeArrays.Vec{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x)
@@ -362,15 +363,26 @@ end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
phi, r = x, y
theta, r = filter_radial_data(x, y, r_extrema)
r = (r - rmin) / (rmax - rmin)
n = max(length(phi), length(r))
x = zeros(n)
y = zeros(n)
x = r.*cos.(theta)
y = r.*sin.(theta)
x, y
end
# Filters radial data for points within the axis limits
function filter_radial_data(theta, r, r_extrema::Tuple{Real, Real})
n = max(length(theta), length(r))
rmin, rmax = r_extrema
x, y = zeros(n), zeros(n)
for i in 1:n
x[i] = _cycle(r,i) * cos.(_cycle(phi,i))
y[i] = _cycle(r,i) * sin.(_cycle(phi,i))
x[i] = _cycle(theta, i)
y[i] = _cycle(r, i)
end
points = map((a, b) -> (a, b), x, y)
filter!(a -> a[2] >= rmin && a[2] <= rmax, points)
x = map(a -> a[1], points)
y = map(a -> a[2], points)
x, y
end
@@ -387,7 +399,7 @@ isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
function is_installed(pkgstr::AbstractString)
try
Pkg.installed(pkgstr) === nothing ? false: true
Pkg.installed(pkgstr) === nothing ? false : true
catch
false
end
@@ -409,20 +421,20 @@ isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.d)
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
ticksType{T<:AVec,S<:AVec}(ticks::Tuple{T,S}) = :ticks_and_labels
ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
ticksType(ticks::AVec{T}) where {T<:AbstractString} = :labels
ticksType(ticks::Tuple{T,S}) where {T<:AVec,S<:AVec} = :ticks_and_labels
ticksType(ticks) = :invalid
limsType{T<:Real,S<:Real}(lims::Tuple{T,S}) = :limits
limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng]
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::Range{T}) where {T<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::Range{S}) where {T<:Real,S<:Real} = T[x for x in rng]
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
@@ -495,14 +507,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 +550,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 +653,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
@@ -621,7 +738,7 @@ end
# ---------------------------------------------------------------
# ---------------------------------------------------------------
type DebugMode
mutable struct DebugMode
on::Bool
end
const _debugMode = DebugMode(false)
@@ -659,10 +776,10 @@ end
extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n)
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + ignorenan_maximum(v))
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
extendSeriesData{T}(v::AVec{T}, z::AVec) = (append!(v, convert(Vector{T}, z)); v)
extendSeriesData(v::Range{T}, z::Real) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::Range{T}, z::AVec) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AVec{T}, z::Real) where {T} = (push!(v, convert(T, z)); v)
extendSeriesData(v::AVec{T}, z::AVec) where {T} = (append!(v, convert(Vector{T}, z)); v)
# -------------------------------------------------------
@@ -680,14 +797,14 @@ function getxyz(plt::Plot, i::Integer)
tovec(d[:x]), tovec(d[:y]), tovec(d[:z])
end
function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer)
function setxy!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.series_list[i]
series.d[:x], series.d[:y] = xy
sp = series.d[:subplot]
reset_extrema!(sp)
_series_updated(plt, series)
end
function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z}
series = plt.series_list[i]
series.d[:x], series.d[:y], series.d[:z] = xyz
sp = series.d[:subplot]
@@ -695,7 +812,7 @@ function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
_series_updated(plt, series)
end
function setxyz!{X,Y,Z<:AbstractMatrix}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z<:AbstractMatrix}
setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i)
end
@@ -704,8 +821,8 @@ end
# indexing notation
# Base.getindex(plt::Plot, i::Integer) = getxy(plt, i)
Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = (setxy!(plt, xy, i); plt)
Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = (setxyz!(plt, xyz, i); plt)
Base.setindex!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y} = (setxy!(plt, xy, i); plt)
Base.setindex!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z} = (setxyz!(plt, xyz, i); plt)
# -------------------------------------------------------
@@ -817,10 +934,10 @@ function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec, z::AVec)
end
# tuples
Base.push!{X,Y}(plt::Plot, xy::Tuple{X,Y}) = push!(plt, 1, xy...)
Base.push!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}) = push!(plt, 1, xyz...)
Base.push!{X,Y}(plt::Plot, i::Integer, xy::Tuple{X,Y}) = push!(plt, i, xy...)
Base.push!{X,Y,Z}(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) = push!(plt, i, xyz...)
Base.push!(plt::Plot, xy::Tuple{X,Y}) where {X,Y} = push!(plt, 1, xy...)
Base.push!(plt::Plot, xyz::Tuple{X,Y,Z}) where {X,Y,Z} = push!(plt, 1, xyz...)
Base.push!(plt::Plot, i::Integer, xy::Tuple{X,Y}) where {X,Y} = push!(plt, i, xy...)
Base.push!(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) where {X,Y,Z} = push!(plt, i, xyz...)
# -------------------------------------------------------
# push/append for all series
@@ -890,3 +1007,43 @@ xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series
"Extrema of x-values in plot"
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
# ---------------------------------------------------------------
# get fonts from objects:
titlefont(sp::Subplot) = font(
sp[:titlefontfamily],
sp[:titlefontsize],
sp[:titlefontvalign],
sp[:titlefonthalign],
sp[:titlefontrotation],
sp[:titlefontcolor],
)
legendfont(sp::Subplot) = font(
sp[:legendfontfamily],
sp[:legendfontsize],
sp[:legendfontvalign],
sp[:legendfonthalign],
sp[:legendfontrotation],
sp[:legendfontcolor],
)
tickfont(ax::Axis) = font(
ax[:tickfontfamily],
ax[:tickfontsize],
ax[:tickfontvalign],
ax[:tickfonthalign],
ax[:tickfontrotation],
ax[:tickfontcolor],
)
guidefont(ax::Axis) = font(
ax[:guidefontfamily],
ax[:guidefontsize],
ax[:guidefontvalign],
ax[:guidefonthalign],
ax[:guidefontrotation],
ax[:guidefontcolor],
)
+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.3"
const _current_plots_version = v"0.13.1"
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
+10 -6
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()
@@ -15,12 +16,12 @@ img_eps = isinteractive() ? 1e-2 : 10e-2
end
@testset "PyPlot" begin
@test pyplot() == Plots.PyPlotBackend()
@test backend() == Plots.PyPlotBackend()
image_comparison_facts(:pyplot, eps=img_eps)
end
#@testset "PyPlot" begin
# @test pyplot() == Plots.PyPlotBackend()
# @test backend() == Plots.PyPlotBackend()
#
# image_comparison_facts(:pyplot, eps=img_eps)
#end
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@@ -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