Compare commits
4417 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 76cf8f0f3d | |||
| 748a913ce2 | |||
| 10f0e83a38 | |||
| 9531fdd122 | |||
| 65a84a7215 | |||
| a6d42d3e0f | |||
| 23ae2c5a17 | |||
| 0e03d7ff95 | |||
| f656179d54 | |||
| 33c734a60b | |||
| 781e6d2a16 | |||
| 4f270fc6dc | |||
| 19bb7340f1 | |||
| 4ac81d12df | |||
| 8bd76ee4bd | |||
| 8ae0d8c808 | |||
| b66e134838 | |||
| 6dbf004d5f | |||
| 928c6d5e6c | |||
| c478c3c9f0 | |||
| a04946e832 | |||
| f9ff2c8962 | |||
| 8190d1fdfc | |||
| cc005c6246 | |||
| 97c43eb031 | |||
| 3907ae7f21 | |||
| c402161845 | |||
| 6fb0d69cb3 | |||
| 1a4bceace7 | |||
| 651548526a | |||
| 1f6089d715 | |||
| 5dde27eb08 | |||
| 52ba52f4e4 | |||
| 60dbf77a96 | |||
| 880190cea1 | |||
| e591332b71 | |||
| 2b44cb5a35 | |||
| d538c4387f | |||
| 60bc127925 | |||
| e6cc826174 | |||
| f257c563fb | |||
| 8a2a41f75b | |||
| da1b9adc17 | |||
| 9d3514224e | |||
| 142bb8cc56 | |||
| fb27704d2b | |||
| 96ed4b2616 | |||
| 6d4353d0b1 | |||
| a2be60b5d1 | |||
| d92990a5f0 | |||
| 99ca1074de | |||
| 8a908c0de8 | |||
| 3c9580fb2f | |||
| 309f2db3b1 | |||
| 0b8755db4b | |||
| ac2fbadc07 | |||
| 535d95334c | |||
| 6332aecc60 | |||
| 8efe35f5f8 | |||
| 493ab0c6b4 | |||
| fa8d437836 | |||
| e95ddc3ef8 | |||
| 50a6dd9fb3 | |||
| 509a8cdc7e | |||
| 672b3a6038 | |||
| 4bcafe3f51 | |||
| 49eba0bf2f | |||
| d0e01a8d88 | |||
| eb1c126dbc | |||
| 6c8fb87635 | |||
| 7b8609ea1a | |||
| f478a649a0 | |||
| 85ca402790 | |||
| 2ebc97d92a | |||
| 2bda216d8a | |||
| ca7f69eaa3 | |||
| fcbfda10fb | |||
| 51df476015 | |||
| c08555a638 | |||
| 93825e2c86 | |||
| c64bbf826c | |||
| 91608a6eab | |||
| 8cc6d9d487 | |||
| 17f3faf672 | |||
| 2e25d86daa | |||
| 0f349be952 | |||
| 8f0d4c4145 | |||
| d61bbcce56 | |||
| 2b376a0e4a | |||
| 62af64f08a | |||
| 882bb1b517 | |||
| a403f9e44b | |||
| 0c4623873c | |||
| d1671ea6f0 | |||
| f905d6b697 | |||
| bc144b64c8 | |||
| 10c94c739d | |||
| 38ada46a43 | |||
| 0e73bcdc4e | |||
| e57a9349f6 | |||
| 120d63f53f | |||
| b885687187 | |||
| 80285061c9 | |||
| fa48e5c490 | |||
| 1fcdac4c9e | |||
| 352df39026 | |||
| 9ab4c31d5c | |||
| e9e6750481 | |||
| bb3e053eb3 | |||
| 0bc41f22bb | |||
| de03c3bca8 | |||
| f2b8e8512e | |||
| 4c95ca5089 | |||
| 9ba633bb59 | |||
| 0b932ecb17 | |||
| f6627f3c5c | |||
| 06a823a3be | |||
| 8c49652add | |||
| 0849471bf6 | |||
| e9a4231a5f | |||
| c9b1de33f6 | |||
| 2013215ef2 | |||
| 8a3ee7bb75 | |||
| eea73202e2 | |||
| cd450f49d4 | |||
| 4b0d69b6a4 | |||
| 02008284aa | |||
| c857d59400 | |||
| b5c8474e3f | |||
| aafb34f5f5 | |||
| 8451b8da0f | |||
| 94ca183a5b | |||
| 2774b155b4 | |||
| 99dff99504 | |||
| 10e83b63b6 | |||
| 2ef9bb1c0b | |||
| a955ded5c8 | |||
| 5861b1f11f | |||
| 7e8eb5af31 | |||
| abebbdd54a | |||
| d1aa2097be | |||
| 9c0b2ea090 | |||
| 60a7e41442 | |||
| a38e4734ac | |||
| 40e13793e8 | |||
| 5d26068eae | |||
| ac8e1d7f21 | |||
| f3b6221daa | |||
| 501f33f5c1 | |||
| 967bc89a6d | |||
| 3b367f8759 | |||
| c43c19a24f | |||
| 445f27a525 | |||
| e7212961dd | |||
| 1402ff5ea0 | |||
| 693c014064 | |||
| 32e681d158 | |||
| d3315a5dae | |||
| 591d485e09 | |||
| d3f2a55b59 | |||
| 092c7376c8 | |||
| dafd0a620f | |||
| e9970637e0 | |||
| 405daa3cfd | |||
| d77899c5a1 | |||
| 711754edbc | |||
| 3725a8d387 | |||
| 93998fee00 | |||
| 9ee2e65225 | |||
| e5d9b8ba48 | |||
| d9c2b7bf37 | |||
| dee3ed263c | |||
| dc7bdc6f69 | |||
| e21f40bd9a | |||
| fe2bae37f3 | |||
| e7c7daff0c | |||
| 6df6b40d3d | |||
| 6286c67c01 | |||
| d89b93fe8f | |||
| e5959d97e4 | |||
| 7a809697c4 | |||
| 2a4f00b80a | |||
| a18809b922 | |||
| dcae18cde2 | |||
| 059fbdfb6d | |||
| 978ffb799b | |||
| ec97ec3994 | |||
| 6cbdd696cd | |||
| e15da664b0 | |||
| 16b9fc08ac | |||
| 5660ea9501 | |||
| 8ce603d3eb | |||
| 54fdd4e177 | |||
| 9b24b38767 | |||
| 00351ebcf1 | |||
| d3343c43a1 | |||
| c0b375a153 | |||
| f5cb54f223 | |||
| e95b2a2a8f | |||
| 8ee5ee062e | |||
| d34b33b4ae | |||
| fdbeace33a | |||
| 26f877ec47 | |||
| 8dc3d9805a | |||
| 08932633d0 | |||
| 959fee92a6 | |||
| 70c4954e16 | |||
| dffb699fca | |||
| 08f993a67f | |||
| c4ee343ef2 | |||
| 17acb45653 | |||
| 842b8fa70d | |||
| e236005d72 | |||
| c7955420e3 | |||
| c9b186c6ac | |||
| 072b6f42f6 | |||
| 86bec68b42 | |||
| 2a09bd8266 | |||
| 2be5756cb8 | |||
| 015b48eede | |||
| 7fe6a69a21 | |||
| 60dcfa9a90 | |||
| 3d2f7571a0 | |||
| 86c26085b3 | |||
| 2d5ad2828b | |||
| bae04d05a3 | |||
| bd287f4656 | |||
| 638fe6d245 | |||
| 3f05dc3570 | |||
| 44150ccbe4 | |||
| c15483d593 | |||
| 363f401474 | |||
| a532c97ce2 | |||
| df07dc9377 | |||
| 9cf9edffe0 | |||
| 2ef13c19ea | |||
| 103f0b28ac | |||
| f157c8dc3f | |||
| ade0a2dfdc | |||
| 71189e113e | |||
| 9fe1f55410 | |||
| 827dba1991 | |||
| 6ac7b41eb0 | |||
| 4c7156ca5e | |||
| 9dfc33dc12 | |||
| 317069e2a8 | |||
| cb54dc071f | |||
| b413f0d44e | |||
| 1784d6179a | |||
| 954f002dfe | |||
| 083fe89905 | |||
| 5906d1c8a5 | |||
| bd46b51b94 | |||
| 63e73bc9f0 | |||
| 915eafcea0 | |||
| 63d9363505 | |||
| 721b4b1312 | |||
| f96e239bc0 | |||
| a13e137770 | |||
| 6a1af1c888 | |||
| 729219f5a0 | |||
| bdcc8cdb8d | |||
| 23b852da8f | |||
| 8255096bce | |||
| abde25efe0 | |||
| efb5816bc1 | |||
| 994b543add | |||
| bb11c62413 | |||
| b8222b46fe | |||
| 1f6244195a | |||
| f4fe4b8a05 | |||
| 514a7c4fff | |||
| 75e65bff8c | |||
| f03e8bbc83 | |||
| fc54177029 | |||
| 5a932146cf | |||
| ba09334845 | |||
| 5ccf1e965e | |||
| e932c76d93 | |||
| 078a675d1a | |||
| 408aad6e35 | |||
| f4c15b4b5b | |||
| d0c709a014 | |||
| bf8b828957 | |||
| 3964cc19a6 | |||
| 3e14a0db95 | |||
| 11f3715453 | |||
| e7ab664120 | |||
| 2aa3e1a5fc | |||
| f58100b400 | |||
| b918c509ac | |||
| 08a4b34c22 | |||
| becd95b9b5 | |||
| f0612ad1b3 | |||
| 46fbff72db | |||
| 0536be3bf7 | |||
| 86561b0af0 | |||
| 747181c370 | |||
| c3f8710175 | |||
| 4cfcef1066 | |||
| ab0cfd09a4 | |||
| cef5b0293e | |||
| 363c842ab4 | |||
| 33832fef70 | |||
| 51527705de | |||
| 44bd1812e0 | |||
| 1e536dda4b | |||
| 6a03da5837 | |||
| 9df962fcce | |||
| b46e460d12 | |||
| e1755dcee7 | |||
| 87c44e231b | |||
| c81fe1ea76 | |||
| 49555ecc2f | |||
| 0425f656ae | |||
| 8fabc5f861 | |||
| 0deb8f6469 | |||
| df12ddb629 | |||
| 33f2f75b00 | |||
| 12e0616712 | |||
| a9eeb451fc | |||
| b854f1cc16 | |||
| 31fb9f09b4 | |||
| 3ba712dde0 | |||
| d38379defb | |||
| 3431833a9d | |||
| 9c4890d794 | |||
| 52cb6fbd3a | |||
| b91aa2bbfc | |||
| c392cc1227 | |||
| a5cd06f3de | |||
| f2e128e8b6 | |||
| a87a5db6d9 | |||
| 744f4d3db9 | |||
| d2c6b800d8 | |||
| 1f4a471340 | |||
| 6b57149619 | |||
| 94e4005b0b | |||
| 5e15ef8ccb | |||
| b1d509cba0 | |||
| 6a3d5202e6 | |||
| ea25f373bd | |||
| e223e9c736 | |||
| f9053ae06f | |||
| 46b4a202e5 | |||
| 79e6096142 | |||
| 08ca46748a | |||
| 5b5e298b84 | |||
| 773f364e0d | |||
| 531e705301 | |||
| b7fedc42d3 | |||
| 3301c4b9e0 | |||
| 312661aae5 | |||
| 977838b573 | |||
| 4052ce83a2 | |||
| 3136c8f999 | |||
| 0b91d51a40 | |||
| 8ffac4d20e | |||
| 85bdca8f1a | |||
| 6ae2d8a291 | |||
| 9334711e19 | |||
| aa6712c9df | |||
| 7515491698 | |||
| 0230e29c62 | |||
| d1cfdd7d3d | |||
| 293fd6caaf | |||
| f97bfbba9d | |||
| 76429cde7a | |||
| 66986a0cbd | |||
| ccec5053b3 | |||
| 72e3cac531 | |||
| 24267ed286 | |||
| c9b8475a9c | |||
| a90ec5975d | |||
| 71ee8d362f | |||
| abb7eb04a6 | |||
| bd7f0dc8d4 | |||
| f23e6c224d | |||
| 449d35ebf2 | |||
| 1b70fb18e4 | |||
| 960e7dbcd9 | |||
| 2dee74a3c5 | |||
| 9d78772660 | |||
| b44735830a | |||
| 448589413b | |||
| f870b01245 | |||
| 48de7e33a5 | |||
| d6bebe1ce2 | |||
| e2c387894f | |||
| bf85afe9d6 | |||
| 217e67fb7f | |||
| 3053bb4cc2 | |||
| 8dcff1f73d | |||
| c73a5aaabc | |||
| 806d4671ce | |||
| c4a64351ca | |||
| 345bceb526 | |||
| 5673ced5d7 | |||
| a929903a63 | |||
| b9cf8c3928 | |||
| 9b573dce49 | |||
| c2bb17cece | |||
| 7e122bdfea | |||
| 1ee999af33 | |||
| 381f14b657 | |||
| 3fec5ae1cf | |||
| b154a1a3e4 | |||
| cef0a55870 | |||
| 61e80e96cf | |||
| 0db321aecc | |||
| 8b7f87506a | |||
| f9f6e0ff57 | |||
| 6f36d0998f | |||
| 943bdca05e | |||
| bece65e922 | |||
| 2fb315af0e | |||
| 849c2911a7 | |||
| fa720d6ad4 | |||
| 1ab681f509 | |||
| 0d776fd09d | |||
| 45e33f5b6f | |||
| 1c4910f90e | |||
| 2f4eb7b558 | |||
| 07ed5e7162 | |||
| 03716289c3 | |||
| 0d38f34e54 | |||
| 2544808000 | |||
| 02ca049bc6 | |||
| cd20518323 | |||
| ff7235e9b8 | |||
| fb5307ace6 | |||
| e3512b0f0d | |||
| 376fae0d79 | |||
| e0e240bfd2 | |||
| 079152a69a | |||
| ffed7ebc21 | |||
| cc7c0f1251 | |||
| 30c683b201 | |||
| c3fa7c8941 | |||
| ddc89e54f1 | |||
| ed2d5be538 | |||
| c0adba6615 | |||
| 22cf3e127e | |||
| 0a929d6022 | |||
| 698f9d8c9e | |||
| f97a5153b0 | |||
| 065089a1a3 | |||
| 79fac7a85e | |||
| a46ffbe218 | |||
| dc81c6aa8c | |||
| fc89578536 | |||
| 6425ff8f4c | |||
| 032f76c69b | |||
| ebaa965604 | |||
| fa44e39030 | |||
| a2aad6be66 | |||
| 3f521b3322 | |||
| 16618430ed | |||
| 4f791a394e | |||
| cfab4e35cc | |||
| 3ea521793b | |||
| 2511d2128b | |||
| d0920ac919 | |||
| acd6cfabc1 | |||
| 86b92698cc | |||
| fb402d9901 | |||
| ddcf443f89 | |||
| 3dd3808895 | |||
| 12df81f390 | |||
| dbd28bc57b | |||
| 171c2f8e33 | |||
| 88c94e11b9 | |||
| 949e245e15 | |||
| f1db5d6502 | |||
| 94086a0ed1 | |||
| 8d67577711 | |||
| 657f6224d1 | |||
| d98481fca8 | |||
| 1c694ca81c | |||
| c52d5e44c7 | |||
| f2a2797c34 | |||
| d14fac5d1e | |||
| 2f8e27ab01 | |||
| 2dce036477 | |||
| f98ef14f15 | |||
| c1ccf16830 | |||
| 0b31e26007 | |||
| 96ec035811 | |||
| 474f0f922d | |||
| 2fcbb093ac | |||
| 8e3f76cb6f | |||
| 07146e84e5 | |||
| 47590b2538 | |||
| d036794576 | |||
| b6234a9ea0 | |||
| d1b2c7f751 | |||
| d353dca531 | |||
| 709a8a9609 | |||
| 0942b14905 | |||
| d6af1da35a | |||
| bbbee44c66 | |||
| 9499cef25d | |||
| 7c8952fadf | |||
| 8b2d3e926a | |||
| fb40ed1f59 | |||
| e88654cca5 | |||
| a9b9b3c357 | |||
| 99c8bfe12d | |||
| 3eb2b783dc | |||
| a20b275eaf | |||
| c29694ae70 | |||
| ebc93b6935 | |||
| 7dcbe911b1 | |||
| c2df99cc66 | |||
| a992effa5e | |||
| e49eb9bc83 | |||
| f2d7d394bb | |||
| 87d40cd34d | |||
| 5f24f88f12 | |||
| 9c465b58db | |||
| ad4a00c055 | |||
| 54671c15d7 | |||
| fff8f84acf | |||
| 4d8ea50f69 | |||
| 43f31cbc98 | |||
| d98e76e36d | |||
| e2a5e40019 | |||
| 3c2c2c18d7 | |||
| 0ee1d867c9 | |||
| b145ea9ef5 | |||
| 73971896ee | |||
| f5f4128e30 | |||
| 70dfa52a9a | |||
| 2e53c57114 | |||
| 0485b1313a | |||
| f0f28086a9 | |||
| 580ac8a9d1 | |||
| 84fc6b0be0 | |||
| de81220c01 | |||
| ee1f948448 | |||
| 995c7d349e | |||
| 4389160a6a | |||
| 8c6295658b | |||
| a270e342b7 | |||
| 42e2266530 | |||
| 02e6d729c1 | |||
| baac9a0578 | |||
| b73dd46521 | |||
| 7bbb2070a7 | |||
| 8859518f2d | |||
| 7f063c71b5 | |||
| 1e9691a7c0 | |||
| e5269bcf95 | |||
| fdd76a6ca1 | |||
| d19525c269 | |||
| 593331dec2 | |||
| b780d90097 | |||
| 2f9ce790e4 | |||
| d8f4519b0c | |||
| 702e41f55d | |||
| 682ac29fcd | |||
| c6ce23d0af | |||
| 9ae7d2dd9d | |||
| 6ec05628d5 | |||
| f26ebdc2f1 | |||
| c97255fc08 | |||
| 9d1ede016b | |||
| 7eb8f2452c | |||
| 0a6e691222 | |||
| 238aca6a78 | |||
| 1f039b3adc | |||
| 219465d599 | |||
| 1963cee94a | |||
| ae43e05f6f | |||
| 5cd2ba7296 | |||
| 4a00018f25 | |||
| 32c725e770 | |||
| 4e2ee35125 | |||
| 35b0751714 | |||
| 28ebc0ccd8 | |||
| 3d693d88e0 | |||
| 6ddf31d465 | |||
| 5c1ea707ca | |||
| a6669f89a0 | |||
| 2a2d509c36 | |||
| fd4efb3f33 | |||
| e90ab0b898 | |||
| 44367c54da | |||
| 3273a65889 | |||
| 0aa606d835 | |||
| 40848e7432 | |||
| fe4cc4d58c | |||
| 56f90ffaf3 | |||
| dfb556339f | |||
| 61f5a7f437 | |||
| 3be9b8d076 | |||
| 2a138dee40 | |||
| 712ef74b81 | |||
| ba8ca424cf | |||
| c6784a779b | |||
| d667cb7e57 | |||
| 10a5c2ed1d | |||
| 8cce78c890 | |||
| 294ade8aad | |||
| a59e8411c9 | |||
| d973f437ef | |||
| d5ce2c1431 | |||
| 834e2a99e3 | |||
| f8e9e33347 | |||
| a0c7781296 | |||
| 2ea998983d | |||
| e44b220b84 | |||
| 756cccb114 | |||
| af9982b804 | |||
| 1b946a18d2 | |||
| a397bfd549 | |||
| d276ac6857 | |||
| 475d1c2398 | |||
| d6ae848aec | |||
| 8976fc4ae4 | |||
| 095191f8e6 | |||
| 83ad031c13 | |||
| 2b1673df6f | |||
| b867ad58f8 | |||
| 8b897c3460 | |||
| e5cb36af7a | |||
| cdaa10be27 | |||
| fe3813b5af | |||
| 311bbdc99b | |||
| c90fa4d63c | |||
| 04c1c6c0ed | |||
| 47a8294d99 | |||
| f3cf8d884a | |||
| fe2d46d1eb | |||
| a0ba0e232e | |||
| 6565515446 | |||
| 65b0f44626 | |||
| b80ba99100 | |||
| 60980f7f7f | |||
| 5132bebc7f | |||
| 275738e7ea | |||
| 5759fd61ea | |||
| 577acbdeb6 | |||
| 4d94725797 | |||
| ad4f92e36d | |||
| 577ac33826 | |||
| 3275719f12 | |||
| f636edf4c0 | |||
| 84039a79de | |||
| d64ba707e9 | |||
| 703bdf6cfe | |||
| e7f79e9144 | |||
| 79fd7f282d | |||
| 3078a44fce | |||
| ba4f2665e0 | |||
| 5504f59098 | |||
| 265439fb2b | |||
| 450b36bdde | |||
| f1e7e3a4de | |||
| becfa33ee8 | |||
| ec5fa44f2a | |||
| 3152d4b4fe | |||
| 66d2e4746a | |||
| 39b10f05b9 | |||
| 5739acd044 | |||
| d1fb11ce97 | |||
| aa46f584b6 | |||
| 7c87cbb425 | |||
| 09de2ebc0e | |||
| 64f7dc1aed | |||
| 122b4d91a8 | |||
| d9efbbcf5b | |||
| d3629f3cfe | |||
| a9c659aa21 | |||
| 5d37264487 | |||
| 2fc6f9220d | |||
| c976a6de83 | |||
| 08c0f6d9a3 | |||
| fafb0d9510 | |||
| df6fa6fd68 | |||
| 8b5fc95443 | |||
| 4e877a206e | |||
| c428dcdb3e | |||
| 77b5951037 | |||
| a1c59b7904 | |||
| 8ae8d74c42 | |||
| eba4d2442c | |||
| d1938c5e94 | |||
| 3dbe5cc3a2 | |||
| 7a6617efe3 | |||
| 123eb15434 | |||
| df13011bd3 | |||
| 3368fd2c98 | |||
| 5a78c492bc | |||
| 8e98d1dfde | |||
| 2373dda3c4 | |||
| 0456ddfe3a | |||
| fe0858ebcf | |||
| 6bc38eaea3 | |||
| 43456b09f6 | |||
| fae1cb4884 | |||
| 9b4c66be9a | |||
| 2d29ab7017 | |||
| 3b3a09302f | |||
| fe92a384b7 | |||
| befe20700a | |||
| 41b34e59c7 | |||
| c01ee17d88 | |||
| 8c9422f470 | |||
| 7c88256ca4 | |||
| f5fe2692e2 | |||
| d00920ca0e | |||
| ef36c6bd0a | |||
| a64d84ae70 | |||
| 9c1b30f774 | |||
| ebfe97a692 | |||
| d8c4210e8f | |||
| a9c0073aff | |||
| d04bb42f7b | |||
| bf849d90a7 | |||
| 95157004b6 | |||
| c861664aea | |||
| 72983102e3 | |||
| 693aaa51d7 | |||
| 41a32f7782 | |||
| 5d99c19de1 | |||
| d942660f91 | |||
| c238d42e83 | |||
| 03a27994d5 | |||
| 1f7773ae4c | |||
| 4a5c82ec7f | |||
| 70f207f5cc | |||
| a1cd3d8f95 | |||
| 848b53e7d7 | |||
| 987456760c | |||
| 4c43f0ea2f | |||
| 7d69795364 | |||
| 059985c91c | |||
| 9fe3428a55 | |||
| 92d8bd7836 | |||
| 2a88ab7726 | |||
| d8f516a456 | |||
| 28ce7d7995 | |||
| b6139e2403 | |||
| 80ec6f03b4 | |||
| 330739298c | |||
| bd9cd64e7a | |||
| f73b281996 | |||
| f180c666d2 | |||
| 908779f0c6 | |||
| 345c3bc928 | |||
| bbdf1dcc0e | |||
| 5da2d85420 | |||
| 5f524d039f | |||
| 824d502c37 | |||
| 36ff017c4f | |||
| 3ef9fe142c | |||
| 4bf0c496d8 | |||
| 9bf4bda852 | |||
| fa7f10a6e9 | |||
| 483e45db8a | |||
| e6097f4534 | |||
| 749f56084a | |||
| 2fa4a63f02 | |||
| 9b1249abce | |||
| bbfc0bc77a | |||
| 5a416e51d2 | |||
| 67ba06cd77 | |||
| aa61d681d9 | |||
| c8e6b967e5 | |||
| 819e91aa37 | |||
| 7f835cf7cb | |||
| 43571e6d40 | |||
| dd3666b6d3 | |||
| f98b191616 | |||
| 9fdcf0db74 | |||
| 7abab41f2b | |||
| a05d31a472 | |||
| 45569c0d4d | |||
| ca653c5bec | |||
| 6c0539bac6 | |||
| 65c9a46c8d | |||
| 7bd97558dc | |||
| 6807f53a7e | |||
| ae396ef576 | |||
| 3dd1c500cf | |||
| 59e4129194 | |||
| 54d441b62a | |||
| f8d36363b4 | |||
| c32c7fda58 | |||
| 87b220e747 | |||
| 57a6f4303b | |||
| 407456eac5 | |||
| f118d0cd35 | |||
| 1b0fb95583 | |||
| 0daed24020 | |||
| 92eaa95127 | |||
| a9d22cfb60 | |||
| b433b76a84 | |||
| 5ff0a419dd | |||
| 6b7be5ae12 | |||
| 9f7474476a | |||
| 8d1f44a0c5 | |||
| 0c101e7d88 | |||
| 5f744dac68 | |||
| 6e3c218d89 | |||
| fe436cf54f | |||
| efdfec13ed | |||
| 52522fde48 | |||
| 2a4882d92e | |||
| bf98db67a3 | |||
| 9f375aef09 | |||
| 1faa858690 | |||
| 5e7d2fb8ba | |||
| 974c6e5950 | |||
| e53f27c224 | |||
| d98262bc08 | |||
| 945874ca7d | |||
| 4c839837d3 | |||
| f230dee72c | |||
| 11a859e83e | |||
| c3a9eb8866 | |||
| 9029e37671 | |||
| 2a4b74d0ff | |||
| 0af25a2684 | |||
| f62f4806c3 | |||
| 22496535d1 | |||
| cb8df169c7 | |||
| ac25972873 | |||
| f1f9d807e6 | |||
| 7d34b9bb46 | |||
| ae009cd53f | |||
| a6aa39e3cc | |||
| dd36d17fa6 | |||
| 9843921503 | |||
| f6feb4b9eb | |||
| 246632abca | |||
| 5da33d7de8 | |||
| 9243de6ce9 | |||
| a5b6c27bec | |||
| 076de033fd | |||
| 1c66f4bf90 | |||
| a1116f8e3b | |||
| d8c4c53567 | |||
| df9217e3b9 | |||
| c5aebf1309 | |||
| dc5ae4ef96 | |||
| d4ecf468b1 | |||
| aa2cee405a | |||
| 5fc02f7f58 | |||
| 3d5ae2fc3b | |||
| eecfdab590 | |||
| e9ef5c852b | |||
| 8594926b67 | |||
| 74a37b7817 | |||
| 13b47a4ee6 | |||
| 0c2d80841c | |||
| d1465ff401 | |||
| ee0a428dbf | |||
| f808a9fae5 | |||
| 932d0da73d | |||
| d9dba5091b | |||
| d9fcfbe80e | |||
| ca3baf3881 | |||
| c37829eafb | |||
| d9a48ac7de | |||
| c684213106 | |||
| 5318352929 | |||
| dd3216489b | |||
| 17db6c01b4 | |||
| 8efd0f00c4 | |||
| b258c9d8c8 | |||
| c94746f3f2 | |||
| b0548ffc14 | |||
| 5194e49b4c | |||
| 2083af9257 | |||
| 6cd8b8ff8d | |||
| ca9e47bc4d | |||
| b6dddcb15b | |||
| ed8e72c1bc | |||
| 4e5e9986a1 | |||
| 55bb6fda1b | |||
| c50a5bf123 | |||
| 2702dc6654 | |||
| 3fe013cd24 | |||
| fba6802066 | |||
| fa8c1e3967 | |||
| 23b191231c | |||
| 2849082f1f | |||
| aa5d514d57 | |||
| 3fb45764b2 | |||
| fcff639d0c | |||
| 96181b8c48 | |||
| 038cf2b133 | |||
| 62290a2a24 | |||
| bfafe91842 | |||
| cbaa8fca56 | |||
| a9e2a5f639 | |||
| f606f083a4 | |||
| b60007cde9 | |||
| 89e271bd91 | |||
| 3ed50bbf0f | |||
| 0d210843e7 | |||
| 08bed07632 | |||
| c47ab69383 | |||
| eb942352ce | |||
| 00379097cf | |||
| 16b568840d | |||
| c1dae9e9d9 | |||
| 8d8921fd08 | |||
| d04d651e55 | |||
| c771739b1b | |||
| a800f8d4d9 | |||
| 4b5ec3ad07 | |||
| 35c68c8890 | |||
| 5005120f5e | |||
| 7b68e7985f | |||
| 871c7d86c7 | |||
| 79614ffcec | |||
| 6821148e8e | |||
| 3255c5a122 | |||
| edcaab3c56 | |||
| c9421be214 | |||
| 9fc707bd94 | |||
| bb9d36eb7a | |||
| 503d741ea6 | |||
| 50984b3bd2 | |||
| 7520c1dced | |||
| bfd468fc3a | |||
| 3ab0078818 | |||
| 1fc587559c | |||
| 4821e04145 | |||
| bb8e62769f | |||
| 236cc4671e | |||
| 15dc61feb5 | |||
| d0d72242cb | |||
| a301366ef6 | |||
| bece5a2620 | |||
| d972702d3e | |||
| d08b33e696 | |||
| da60b47af5 | |||
| 0ac63857c4 | |||
| d08422811e | |||
| d5788fc1e7 | |||
| 6da5bb8822 | |||
| a0a3b42872 | |||
| caf0aa098a | |||
| 55ea8b4a70 | |||
| 25c53f0e52 | |||
| 7c3938f793 | |||
| 20a10fcf7d | |||
| 6ee49f8430 | |||
| 0768c8a658 | |||
| 89b2be4ecb | |||
| 369d510b3e | |||
| d1dbb1bf2a | |||
| ccf726ddcb | |||
| 5b2cd1b8ee | |||
| 16b8d01b88 | |||
| 8d7b07eab3 | |||
| 599d6a2ec8 | |||
| 345f5654a3 | |||
| 77e04c45db | |||
| ad4d7214e4 | |||
| 4051d016b9 | |||
| c1959cb993 | |||
| 8610a82a88 | |||
| 4832d870dd | |||
| ace915fbfb | |||
| c6593423f5 | |||
| ecf71a43d3 | |||
| b65dfc6767 | |||
| f69daa8cfe | |||
| 71246620aa | |||
| 6e3181375c | |||
| e7b1dc0cac | |||
| d78bb56316 | |||
| 648c5ac587 | |||
| df7d28dc99 | |||
| 4d28a49c70 | |||
| ef3e7af329 | |||
| 3221b80aeb | |||
| 13fc936e1f | |||
| 4e5b1aa6e5 | |||
| cb577f0ef3 | |||
| b23dd39e06 | |||
| 7498b3c769 | |||
| 0c0a2c215c | |||
| b682bc8e96 | |||
| 205345a8d3 | |||
| faff9cebe4 | |||
| bcd1bc1009 | |||
| f2ca493a14 | |||
| 54301fa97a | |||
| 20a290792f | |||
| 31f5490517 | |||
| 8554e632bd | |||
| 70d0d786e2 | |||
| 5af5ec7313 | |||
| 7fab2f1c6b | |||
| 461ef20225 | |||
| 4357fde5ea | |||
| f93977b1a4 | |||
| 2e77d0df98 | |||
| fc40b0e0ac | |||
| 85aca2aa67 | |||
| 961d6be9f9 | |||
| 33553eb055 | |||
| fbe8dcaf78 | |||
| b5f54afed2 | |||
| c99fcc3dcd | |||
| 4a7ea82862 | |||
| 3bad6e9b4c | |||
| 96ab1537d3 | |||
| c62714d188 | |||
| 2b6a90766a | |||
| 366d598ff0 | |||
| 84a8039022 | |||
| 8011c9f675 | |||
| d709b53ec7 | |||
| 39c97ecdc5 | |||
| 45c434b5ed | |||
| 312f98e380 | |||
| d093d1ad7e | |||
| 22e8718e85 | |||
| e489787535 | |||
| 73ff286162 | |||
| c75f6f5a9d | |||
| 33d04c3e6b | |||
| 2ede388c15 | |||
| 745189981b | |||
| dd70192de4 | |||
| 5fc2f6cf3b | |||
| 2c6f54579d | |||
| 9bcab45cb8 | |||
| 3b7464e739 | |||
| 11c86b2d30 | |||
| 7a521ef21f | |||
| 7fb1a6a517 | |||
| f20582e528 | |||
| 92e609876d | |||
| 5a251e5702 | |||
| 33cf0e66ec | |||
| 9d75916244 | |||
| 6ed18617d5 | |||
| 2022aebb07 | |||
| b73c38fe69 | |||
| 11322d0d8b | |||
| 82479d48b9 | |||
| a07fd5d3db | |||
| 10ab3ae974 | |||
| b908202c47 | |||
| 61d4c84ef4 | |||
| 68a0baf299 | |||
| aef75cb073 | |||
| c5fe90d135 | |||
| 85e5f2e971 | |||
| 58bf14fc85 | |||
| 0d09975fba | |||
| 06afcedf56 | |||
| c7cc76b2b6 | |||
| 84b108f6d0 | |||
| cb6f0772b7 | |||
| 4263ced69b | |||
| f5c6b06eb6 | |||
| 05ef841d63 | |||
| 140afeb53d | |||
| 639a09bccb | |||
| f105d41e54 | |||
| 140a429e09 | |||
| 28d5e0bb7d | |||
| 3dec7fe394 | |||
| e54eb53665 | |||
| 9b3cf3a818 | |||
| 3d306578f1 | |||
| e615718f1b | |||
| fbbbd40353 | |||
| 0e694a9767 | |||
| 203e351cef | |||
| 74ec895aca | |||
| 3459bcd817 | |||
| d2c0840c43 | |||
| 9534bae4ef | |||
| 2a720a7491 | |||
| 7b31e5f9b8 | |||
| d0be1e7d1d | |||
| 8434741599 | |||
| cfe1ede25a | |||
| ecc891279e | |||
| 750f96cca7 | |||
| 5051e06be0 | |||
| cde041e977 | |||
| 0fdf46fd2e | |||
| c902c3ff35 | |||
| f0b006d3c9 | |||
| 044daf08d4 | |||
| 0b5b8b2cc2 | |||
| fae5c45cc4 | |||
| 3bc8ffda58 | |||
| 589713cb75 | |||
| ca9ce5427d | |||
| 374809d3cf | |||
| e1d45dec5d | |||
| bf60d6482f | |||
| e04858c975 | |||
| e0148ba1a8 | |||
| ee521107d3 | |||
| acbce64be9 | |||
| bb11426274 | |||
| 2249aaafdf | |||
| 172193e706 | |||
| 93d7e53f8b | |||
| 7e05bb0aca | |||
| a1130efa2f | |||
| e903514f70 | |||
| 87f2b0154e | |||
| 0ab42eb008 | |||
| 39e93f40c2 | |||
| 0458c18c13 | |||
| a3fc47a7de | |||
| 715181585a | |||
| ecadf4c8f6 | |||
| 899c8b3634 | |||
| 68b344e7c3 | |||
| 58cf8e471e | |||
| 68b29f63a6 | |||
| 985d43bf4c | |||
| e3239bf312 | |||
| 39cb3733db | |||
| f9ea9cd999 | |||
| 47900b1a80 | |||
| 9488176a2d | |||
| 091ca327ba | |||
| f2af121661 | |||
| fe07fe0a7b | |||
| c4354c86c0 | |||
| 7ea1eebc9e | |||
| 3d73591178 | |||
| 5335159203 | |||
| 7b2be59b7b | |||
| 3eafc67654 | |||
| acf4cb4e5b | |||
| f53b070d79 | |||
| aaaedcab1a | |||
| 02b54e72a6 | |||
| c034d7bf1b | |||
| 8636718c88 | |||
| f11d5b1e63 | |||
| 903fb84af0 | |||
| 92814e71c7 | |||
| 35e24fef2a | |||
| 95a29f9cbe | |||
| 6ba1607bb1 | |||
| 2bbaf9d504 | |||
| 607640ce73 | |||
| 195c6d601c | |||
| c39a6d8ec3 | |||
| 42e88225c5 | |||
| b9b6915855 | |||
| b2852802db | |||
| ced201700e | |||
| 6d737dea7b | |||
| 311ace523d | |||
| d6bd10a937 | |||
| a03ae0be10 | |||
| faa401f0e5 | |||
| 6378f88ba9 | |||
| f5cbb1e341 | |||
| c9c4de37e6 | |||
| 567d3688e8 | |||
| e3a166f04c | |||
| 74001a555b | |||
| 4c6b96e38a | |||
| 1f14a4d4c6 | |||
| 242d8b290d | |||
| 2cfd1838ca | |||
| 642bb9aead | |||
| fc0a12ac36 | |||
| a2bdc4c3ef | |||
| faf905a932 | |||
| 1ba5ad0e90 | |||
| 59ad0d830b | |||
| 1fcd06f903 | |||
| 66e8f6615e | |||
| 10e7cb8eba | |||
| 3c9a7193fd | |||
| 424b98e1a1 | |||
| 57db8095c4 | |||
| c0e68af63f | |||
| f2f647c642 | |||
| a117bbc04b | |||
| abc212b039 | |||
| cb1d32422a | |||
| 0dd970fc6b | |||
| ce1276bcbd | |||
| c2c1c9d738 | |||
| 6d3e8fcb81 | |||
| 7954adedf3 | |||
| fc6dfb8dcb | |||
| 7f1863f3b9 | |||
| 9fb6b8059f | |||
| e34570e307 | |||
| 32d712ce29 | |||
| bc42001b75 | |||
| 914d3cac44 | |||
| 10868ef565 | |||
| 046643f743 | |||
| 1ef4cfb86a | |||
| 9324123b4d | |||
| eddf523d08 | |||
| 37ff1a73ed | |||
| 91d4e9dbe2 | |||
| 0821ad3c03 | |||
| bf2e5d3fdc | |||
| 7e54cd4306 | |||
| 6ecf783fd5 | |||
| b45c336063 | |||
| 4d9dc31c5e | |||
| ec4420cb38 | |||
| 243ff2d59e | |||
| cc2e8ed513 | |||
| ca0c78fe5c | |||
| e5b678f4a8 | |||
| fe7989798c | |||
| 12efedf3e3 | |||
| 25fec470a7 | |||
| 6d148b05a3 | |||
| 4c3002e72d | |||
| cc4750688e | |||
| be5cd7de2e | |||
| 0d2ccfddfb | |||
| fa6f0a6b00 | |||
| 0b71f55b29 | |||
| 9cdc72662f | |||
| a37d9768a0 | |||
| 7de8d302fa | |||
| e29edc9e97 | |||
| 1e216291ab | |||
| ce5c36ded5 | |||
| 568c4a0228 | |||
| 0c5e561eac | |||
| d796812161 | |||
| 26905b18ac | |||
| 7fc7471f81 | |||
| 3272f72df0 | |||
| ab8b57ed49 | |||
| eb7ac6ea3d | |||
| c056f8525d | |||
| 024a11f35b | |||
| 33390a2c2d | |||
| d409ad22a0 | |||
| c600cb0294 | |||
| 077f1ddb84 | |||
| a9cbe354c1 | |||
| 44341d1ff5 | |||
| e2a4b0eb30 | |||
| d2ca5e3bf3 | |||
| 8cb32b1f14 | |||
| 8553bef132 | |||
| 20f6d559c3 | |||
| d50c28ebe7 | |||
| 1c854519c8 | |||
| 229f74e370 | |||
| fa324561da | |||
| e176c6c315 | |||
| 3b56977c49 | |||
| 5482cfac3f | |||
| 04e5ff7eba | |||
| e230686851 | |||
| 5694ce53f6 | |||
| 4dd4d5eb5f | |||
| 0e94e57263 | |||
| 7bf89d8614 | |||
| d47e8c0f44 | |||
| 48c04a5a44 | |||
| 31bc74e2b1 | |||
| 1e23b8d475 | |||
| 48208998e2 | |||
| 92aafb1349 | |||
| e1e8a480f9 | |||
| b6e641c035 | |||
| fe77659058 | |||
| b645ca984f | |||
| 46a3f2e495 | |||
| e4e9cbf6cb | |||
| d43e53f896 | |||
| 2d947f4a97 | |||
| 71720de7b2 | |||
| 4964eb31fa | |||
| 0b8f7d67dc | |||
| faf6ea72e0 | |||
| b66415a338 | |||
| e14733d460 | |||
| b6f7c8bc4b | |||
| 91aef71891 | |||
| 408db8dc4f | |||
| 4902716a44 | |||
| e084c1410c | |||
| ea790cc7c5 | |||
| c0fc671a83 | |||
| fb418c87ac | |||
| b6da96fb78 | |||
| 1a751c7bae | |||
| 2d100d8261 | |||
| 3f70fdb3aa | |||
| 1819e3dd99 | |||
| 64791017f8 | |||
| 5e0d42898c | |||
| 4486620918 | |||
| b6bd69055b | |||
| 1e2ea1614c | |||
| ea74fcd4d6 | |||
| c39613ddd8 | |||
| 4a4f9dff6a | |||
| cd55218a2c | |||
| 881d415f21 | |||
| db02ffa436 | |||
| 2c78f1ff7b | |||
| 2bf3ddf45b | |||
| d8c48f1a85 | |||
| 1f566294ac | |||
| 86643058b6 | |||
| 6b6d589aa7 | |||
| cbc0419c6e | |||
| 5920f3b34d | |||
| c472ecf3b0 | |||
| 70c507b8f8 | |||
| 2245e572aa | |||
| c984722807 | |||
| 97c0161b9d | |||
| 05eed0fdda | |||
| 9e74976d6d | |||
| c8b75dfae1 | |||
| ca600e9d76 | |||
| 94812cde7a | |||
| 3db930cb93 | |||
| 37300a9345 | |||
| 54fc1ff69c | |||
| 6d1c723e4b | |||
| eab5091147 | |||
| b8f21ad878 | |||
| cb4702f7b8 | |||
| 25313f6b43 | |||
| a0e0c2c950 | |||
| 8b43f70ed4 | |||
| 867a2b8748 | |||
| 63cd86589c | |||
| 31c4414c32 | |||
| 36558389b6 | |||
| 686ab1b51f | |||
| a728ed9a60 | |||
| 00fd916595 | |||
| 7c5b7b09c2 | |||
| c3c63971ab | |||
| 5c1c80fd9a | |||
| c9a9541d0e | |||
| 224858dad5 | |||
| 8a9e963d92 | |||
| 464c0271f0 | |||
| 798d78813a | |||
| 6b0e45c450 | |||
| cf8bd786d0 | |||
| 9b4a51c5be | |||
| b58c52f12c | |||
| 17eef46da2 | |||
| cc14ab20bb | |||
| 978f00bbb9 | |||
| d0a73eb862 | |||
| 0ca5a30b8a | |||
| 76c7d9dc89 | |||
| 653e0b80b2 | |||
| 8b0fc1629a | |||
| a76e756f4f | |||
| f632cd48a4 | |||
| e12b0a585c | |||
| 151ce619dc | |||
| 28903d5db2 | |||
| d179b5d6bf | |||
| 12df8fa500 | |||
| 99293ba5e6 | |||
| 2dc3096ee9 | |||
| 926a023b1d | |||
| 4f705a6e58 | |||
| 74beb86530 | |||
| a55f8d0099 | |||
| caca1b2e3c | |||
| 62fe5d003e | |||
| 216dae97fc | |||
| 07ffa8c117 | |||
| 62dc012c66 | |||
| 831987c76f | |||
| 32b85d48c5 | |||
| f6d37afba0 | |||
| 3b962ffb08 | |||
| 2c3bffaf76 | |||
| ba8110dc20 | |||
| 55e17a4a65 | |||
| 767b8b245a | |||
| 2ea37776ed | |||
| 03d2f704c5 | |||
| f7e19bcf63 | |||
| 1e0fcbc65e | |||
| 5d5c4d76b9 | |||
| 871561afd7 | |||
| 1da4b2eda9 | |||
| 9775abecc2 | |||
| 1650049b88 | |||
| d7cc15d391 | |||
| 57286ea40d | |||
| 5ad4c517e1 | |||
| eba6e29092 | |||
| 7dc6ea355c | |||
| 3e31c4363f | |||
| 61e3abaf80 | |||
| bd8e9dc947 | |||
| 236aaed2a3 | |||
| 37044e5fc8 | |||
| b05d6e2ed3 | |||
| d28164c897 | |||
| 6c68b6f6fe | |||
| d0c6f0d6ee | |||
| 150b5a1f06 | |||
| 8ea6d70433 | |||
| f8ee4da180 | |||
| 4a57f462bc | |||
| 11ae5ea014 | |||
| 4cb3e6a23c | |||
| dd645bcd9f | |||
| bccf4ef563 | |||
| 85e2534e93 | |||
| 2c57e0c958 | |||
| cb161a25da | |||
| a4380586e9 | |||
| f2a583a599 | |||
| 3ea4c8d9ca | |||
| 30f321d88b | |||
| 1db3b69489 | |||
| 3a775315b9 | |||
| 1ed9bcae5c | |||
| 03d57e690c | |||
| 4247584df2 | |||
| 844c3f7002 | |||
| ff774dc409 | |||
| 9fd7a84b48 | |||
| e555f679c1 | |||
| 89613bfee5 | |||
| 3fdf87a955 | |||
| 0f07975857 | |||
| 48a245559c | |||
| 648f26f075 | |||
| 808e20588e | |||
| 82dd5bf3eb | |||
| 0950c738e3 | |||
| f12f6db310 | |||
| ae4031b993 | |||
| 2495d2a1e9 | |||
| 0a97b08c72 | |||
| e0a89c55ac | |||
| 75ac34b719 | |||
| 2072c54c53 | |||
| 6e1ed63005 | |||
| 17e59daeb4 | |||
| 69e83ef89f | |||
| b2707f5c8a | |||
| 0fd24e5210 | |||
| 3dcc7e5556 | |||
| 57ebeae1ad | |||
| 9e35cc3fe1 | |||
| 3e1258aa0c | |||
| 96e1b1d105 | |||
| fe80e486aa | |||
| ad051f21c1 | |||
| ac24a4ae19 | |||
| 7ae43ee9f6 | |||
| 0e79070ad8 | |||
| f11b976574 | |||
| 59da5d5deb | |||
| 0deb7038e6 | |||
| 2ef692c690 | |||
| 9228c0b9ec | |||
| 89d02b1d67 | |||
| a63a9248d6 | |||
| 79777adc07 | |||
| 5619feb6c0 | |||
| f15a721db6 | |||
| d6b3b68cd9 | |||
| 78785fa8fe | |||
| 74c69f575f | |||
| 12e34bb24f | |||
| 4ac5484b4f | |||
| 8306619faf | |||
| 5673477428 | |||
| 84c5b67574 | |||
| e71a15d46e | |||
| daf9556bed | |||
| b6a7c1036c | |||
| 8c2a66b00c | |||
| a1182e0ebe | |||
| 750492f9e3 | |||
| c6893f6cb5 | |||
| 64e035c53c | |||
| adbe515af7 | |||
| f0dac1630f | |||
| ddaa69bce2 | |||
| bb7c2fd660 | |||
| 8dfca61769 | |||
| bb3c54cb27 | |||
| 2816b1128f | |||
| cf0cf972e3 | |||
| bb0e783c02 | |||
| a7b7c5ba81 | |||
| 7214b8b1b1 | |||
| db1e25252a | |||
| 7a248331e7 | |||
| 161ffdee94 | |||
| b3e8fd9c66 | |||
| 538135bc5f | |||
| 0aac0398e8 | |||
| 552024ff31 | |||
| 2f14c37c59 | |||
| 7f8dc486bb | |||
| a89b42229a | |||
| e061d156bc | |||
| 8f4753a0bb | |||
| 068523fac1 | |||
| b3336229ab | |||
| 3614966241 | |||
| 80c1cb954d | |||
| 0f6336b3dd | |||
| cd1ee47ace | |||
| 46ed2f6263 | |||
| 63f6128c87 | |||
| 9f9ac4ec92 | |||
| 7cf223a5b8 | |||
| 9a6e0b3a54 | |||
| 589643d591 | |||
| f75ae01c16 | |||
| 3509648553 | |||
| 94841669bf | |||
| fadc0bf6c7 | |||
| fd2c01808a | |||
| 8342da1ea2 | |||
| e9abb6d021 | |||
| 505989eec7 | |||
| 08a30b255d | |||
| 1543c77a39 | |||
| 4c22a421a1 | |||
| 972c97d5ec | |||
| fd611b3647 | |||
| 71cbaa843c | |||
| bbf8b50ad6 | |||
| ddd083b8c1 | |||
| 03f6c76b53 | |||
| 6d6d4f14b5 | |||
| 0735a3475c | |||
| 9a445d529d | |||
| 1ea5a5ac0b | |||
| bc8370eadd | |||
| cdc5a2b361 | |||
| 4270ac80fb | |||
| 405df5da8b | |||
| f742ae4c88 | |||
| a99783dfa0 | |||
| 9af5edd04d | |||
| d0830b90be | |||
| 8cd48bc660 | |||
| 379a320d2d | |||
| d5f3a3ef69 | |||
| a3be970f29 | |||
| 63f8f52c9f | |||
| 169851564c | |||
| c32b9029d1 | |||
| 3fe60b9d18 | |||
| 34cff752f1 | |||
| 0dba83daf6 | |||
| c399092261 | |||
| dcabb2c579 | |||
| 3542785021 | |||
| 65173e6dd2 | |||
| bf0bb68e28 | |||
| 21774dc36b | |||
| 0e3a9f0b8f | |||
| 903cb404c3 | |||
| 03325533bf | |||
| 710123aab4 | |||
| 4742ec972b | |||
| e860ba220a | |||
| 39605bccc2 | |||
| 1a4f411b8f | |||
| a6588daa3e | |||
| b053366b06 | |||
| e838ac502d | |||
| 6131154dd0 | |||
| 0c67a61e7d | |||
| 72696a4326 | |||
| 3231f4d9b1 | |||
| 8a81b398cf | |||
| a37a1a0004 | |||
| b6b00c843a | |||
| 5506c0543c | |||
| 7a1b48311c | |||
| 0b3dafcd18 | |||
| 81f6b3c7bd | |||
| c2da4acb48 | |||
| 841b05631d | |||
| a6e60aea04 | |||
| 7f2a1db64a | |||
| 926ccdf618 | |||
| 9774eca8e2 | |||
| 2ad033f8e2 | |||
| 7c26ffee51 | |||
| aa37ba0463 | |||
| d61c86b54b | |||
| e72fa1dc74 | |||
| 16db531cce | |||
| 226023043b | |||
| 5d2538c4c2 | |||
| 0075103ddf | |||
| 8982a67902 | |||
| 65ab45ff1b | |||
| 577d434bc8 | |||
| b300e634f6 | |||
| 61d13b9b2d | |||
| 78059bf825 | |||
| dd02a69e8f | |||
| 5ec80ad1f1 | |||
| 4849772435 | |||
| 6546879d3a | |||
| cbc379daa9 | |||
| a7be08ef46 | |||
| 47e48e5d27 | |||
| 968b8109dd | |||
| 19fba27951 | |||
| b78da20d04 | |||
| 5e445b4a71 | |||
| 0e5df883d0 | |||
| b79ea119ea | |||
| b21d98affd | |||
| d83666bed3 | |||
| cab6ca3ef0 | |||
| 33a37f9494 | |||
| 79e978aac9 | |||
| 3af60a81f8 | |||
| 56525ced92 | |||
| 581f3797bc | |||
| 2c8d51988b | |||
| 19243b741a | |||
| afc1e08f21 | |||
| 80c01e74c6 | |||
| d728bfb90c | |||
| 203d73ee26 | |||
| 05fe220102 | |||
| c4f2de198e | |||
| 50f9846836 | |||
| a33b3cfbd8 | |||
| 248f7cce90 | |||
| 8f381e2611 | |||
| f4b14d0d8d | |||
| 93428815e4 | |||
| 6b70610770 | |||
| 84eead47e3 | |||
| 009d03f1f8 | |||
| 9482a247e7 | |||
| 022c79fa95 | |||
| a9ed4ac21d | |||
| 354e39e9bf | |||
| 757e08c6fe | |||
| 33e5775294 | |||
| 5b73a8ed1c | |||
| f864ebbf1a | |||
| 54b6051315 | |||
| ebea34920b | |||
| 44294306ce | |||
| c2af1a0666 | |||
| 8f30696a4d | |||
| b58082a37b | |||
| a594878860 | |||
| 3a2b6296ac | |||
| 87af609a6f | |||
| a0d5d0f3c8 | |||
| 53510f3268 | |||
| 9d5ce9753a | |||
| d7a2df41fa | |||
| f905cb9577 | |||
| b9b6439f47 | |||
| ffcdf986a3 | |||
| 43245b5eb5 | |||
| 420228c67b | |||
| f1719d6e91 | |||
| 9aa1fd5c00 | |||
| 141845aa40 | |||
| 7867df6079 | |||
| 182b937143 | |||
| 5a54fb7e9f | |||
| 399a9b16f6 | |||
| fef45dfc30 | |||
| 42aa7d8d55 | |||
| 8778119792 | |||
| 10e3f2c990 | |||
| 5e25989366 | |||
| f12d328cf7 | |||
| efc4917724 | |||
| c2bf145ff5 | |||
| c8c82811b3 | |||
| c21e133e69 | |||
| 789a7fbb88 | |||
| 888ed9f0ae | |||
| 57da253fa8 | |||
| 44a6707397 | |||
| f0a3ca4314 | |||
| 9bbd52dcc2 | |||
| f50862ac51 | |||
| 017bed1a07 | |||
| 3765d5f549 | |||
| dd28159564 | |||
| 63cdf9f8e7 | |||
| e30889aa12 | |||
| b7caec1bfe | |||
| 660786b99c | |||
| b060576209 | |||
| 7b3826c2d5 | |||
| 51d4416b00 | |||
| cfe6103f48 | |||
| bee8230079 | |||
| 3d77c59c92 | |||
| 667ed161c0 | |||
| 979f9495f1 | |||
| d29a44efa7 | |||
| 7750003033 | |||
| e673339dc4 | |||
| b20b47f8eb | |||
| 689e437bac | |||
| e6bb17dc86 | |||
| 80a97b0f26 | |||
| ffea050bc2 | |||
| 8951526d0d | |||
| 3e799fbe21 | |||
| 53e27dbc38 | |||
| 9985d303ce | |||
| ba46299088 | |||
| 9679eae662 | |||
| 7acb5a4bdb | |||
| d1428b8221 | |||
| c59a361ab3 | |||
| 8935728daa | |||
| 155ac91385 | |||
| 4403ed3860 | |||
| 712b567752 | |||
| 75be945359 | |||
| fe50a457cd | |||
| 6f821e5344 | |||
| 14cbfb5706 | |||
| a882685169 | |||
| b9b7edc72d | |||
| d0b939da4a | |||
| 2643d493a3 | |||
| c26689fcb1 | |||
| a2365f2c14 | |||
| 435ff795ca | |||
| af34fdc45a | |||
| 3bfedd844e | |||
| f726151e6e | |||
| c6c4becf7d | |||
| e2deb71988 | |||
| a717bf4f34 | |||
| 2fef7a5b84 | |||
| 12309c281b | |||
| a2a4e5b350 | |||
| 6741287ef1 | |||
| 6940f5a982 | |||
| b0bd5c13a0 | |||
| af119a0248 | |||
| 759cd7b3f2 | |||
| 5e06e0d2d2 | |||
| 85b83e1745 | |||
| 441954be35 | |||
| 11c1a23dfe | |||
| 1386435b17 | |||
| f33d135182 | |||
| 5396477082 | |||
| 5ea77cc4b6 | |||
| 45b5b33929 | |||
| 9213b09c57 | |||
| 113e616d25 | |||
| 8861c553da | |||
| 6be7995500 | |||
| 89d08606ad | |||
| e709560319 | |||
| 9eda7548d0 | |||
| 6e0522308a | |||
| 7062e8864b | |||
| 957cea2638 | |||
| 532710e6bf | |||
| 24e46e4c01 | |||
| cb3cdbf6e7 | |||
| dcceef2e52 | |||
| cbc965dc53 | |||
| f5b793f80c | |||
| d3b51703f2 | |||
| 0ecee70af2 | |||
| 061704ac6e | |||
| 3e1ce8c2fa | |||
| 1cc84672e7 | |||
| 04f502df8a | |||
| 22c3afd8a0 | |||
| d9be97fc45 | |||
| b04e6ff699 | |||
| 9c1a5548e1 | |||
| b73d7f03a7 | |||
| 106ed6b953 | |||
| cccbaa0bdc | |||
| 874dacd2c8 | |||
| a72a23b548 | |||
| 31004e8c12 | |||
| 87c471c0f5 | |||
| d3e1a423fd | |||
| 16cc743d26 | |||
| 9ccb699fca | |||
| 7e0960e7a0 | |||
| ee4fc2803b | |||
| 268c2861c9 | |||
| 15739bc0ee | |||
| e84de56f2e | |||
| 6b46e81fbd | |||
| f5de5f58ce | |||
| 3c2cfa333c | |||
| 63bc3a2b88 | |||
| 1e83bc05ee | |||
| acb9faa6e3 | |||
| 732103abf7 | |||
| 90223ff514 | |||
| ec8084823c | |||
| 05b55fa8dc | |||
| eaad735d22 | |||
| ecf483702f | |||
| 2e9e1fc424 | |||
| b5c73d1574 | |||
| beb73d891d | |||
| a4edd8e41f | |||
| cac3dae96c | |||
| 279ef2075f | |||
| 5d0740c0e5 | |||
| 9ee8055093 | |||
| 07ed7eb6dd | |||
| ed6878a48f | |||
| 09a17ba783 | |||
| 046b291c1f | |||
| 187a19bfd1 | |||
| 91816e6715 | |||
| 13339125eb | |||
| 3197db9fc1 | |||
| 6e4aac1123 | |||
| 94450a26e9 | |||
| f571596eda | |||
| 8b6ca96e0a | |||
| 198de2607a | |||
| 7cd1c9e8c8 | |||
| fc51c355a5 | |||
| 59e7213c96 | |||
| 192020a93a | |||
| 5f5019d310 | |||
| 9aa201dcb3 | |||
| f0f90d87af | |||
| 1bbe800dcd | |||
| a731ef6e2d | |||
| 25b09a7962 | |||
| 80151ac1a3 | |||
| bad5668ff7 | |||
| cad0f15aed | |||
| 9c42c30d8a | |||
| c471d1e4c3 | |||
| 7ae4fae68c | |||
| 2405d5151b | |||
| 4f667291bd | |||
| 49ad3a51aa | |||
| f2e98acc65 | |||
| b68adde751 | |||
| 7220eca7a8 | |||
| 10dd9b5120 | |||
| 7590c133fd | |||
| 2873685517 | |||
| 9887892a92 | |||
| 6fa15751ae | |||
| 24e3fcbb6c | |||
| 91f51778f1 | |||
| 5c2bf5d76c | |||
| c4233e2896 | |||
| e0b7bdc1a5 | |||
| 91ec39e141 | |||
| 602dbdf1d2 | |||
| 3eabaf074a | |||
| a81178121f | |||
| e1a83aab1d | |||
| 84601bacdb | |||
| e991e2bf37 | |||
| 9b6fc4bc6b | |||
| c9e832600c | |||
| 25190d945d | |||
| b2f2ffcfed | |||
| 00821c1ae3 | |||
| 937acbc218 | |||
| e0f9313b8b | |||
| 6d0d8ea90a | |||
| ebf32390ef | |||
| eefea15069 | |||
| 531dd43284 | |||
| e483ce85dc | |||
| 80da14c1fb | |||
| 374580a3d6 | |||
| 4a51e4e7fb | |||
| ae969dad38 | |||
| 7fcd008f2f | |||
| def5be630a | |||
| de3848ff53 | |||
| 8d4ab6bb94 | |||
| 28ac117d68 | |||
| 065ff48b15 | |||
| 69bdd6db83 | |||
| cd270dd407 | |||
| b4944a6f81 | |||
| 4049bf20c2 | |||
| 805ca0d378 | |||
| fcaae346a7 | |||
| 0684102511 | |||
| 6ca87f6d33 | |||
| 3c96831cdc | |||
| b551f6714b | |||
| c005cc211f | |||
| 92b0d5c0be | |||
| 45dc9e5c0d | |||
| 7c505949fc | |||
| 905accdb7d | |||
| 30f3e3cf56 | |||
| 71131fd00c | |||
| 60b8b0080c | |||
| b30ff9b41b | |||
| cf1a0e3c33 | |||
| e94fe13178 | |||
| b2c4561a7d | |||
| ef63c8d66e | |||
| 00be8a2237 | |||
| 6593e3cfe6 | |||
| ac73798b9d | |||
| 1697b99bbc | |||
| 1e9467a221 | |||
| b56238089c | |||
| 47d8aa871b | |||
| 87627b8320 | |||
| c419f87b64 | |||
| 9ae22a1ad7 | |||
| b4dfd35be6 | |||
| 916654b3ec | |||
| 2acd088226 | |||
| 2d217edc15 | |||
| b55d13bc21 | |||
| 1f9468e029 | |||
| 593804096d | |||
| befb14682d | |||
| 07a6700ab6 | |||
| 8131953e49 | |||
| 7e360aa915 | |||
| 0710fba638 | |||
| ad1bcbb0ac | |||
| afb7a17e5f | |||
| badf302756 | |||
| 99941dde8f | |||
| e5c55b6962 | |||
| 7a7f4cb306 | |||
| c0ff8f80b1 | |||
| d084e31065 | |||
| 12008ef1c6 | |||
| 23ec52c6b4 | |||
| 5485740291 | |||
| 6dc0823b73 | |||
| 0f9220c965 | |||
| 5c21261aea | |||
| 1fda0df03e | |||
| d4406bb806 | |||
| b1095e29bc | |||
| 3e56aa43e4 | |||
| c2dc030fae | |||
| 5565680b53 | |||
| 340cd0a1fe | |||
| 2844e706a9 | |||
| 55ee64b4e6 | |||
| 3849700a28 | |||
| 3dd0049973 | |||
| 8e6ccf1b20 | |||
| c544dbbbb7 | |||
| 5205ac38ad | |||
| 0143807515 | |||
| 5176ab1382 | |||
| b0d54f7c5d | |||
| 96f0335af4 | |||
| 572f8ebfde | |||
| 07a8d844d2 | |||
| c48abef5f8 | |||
| 9b3679792d | |||
| cb00983db3 | |||
| 83686866cc | |||
| 7a49249384 | |||
| 0548793bfd | |||
| cd770f70c0 | |||
| a3f1950a18 | |||
| 1874c28cad | |||
| 317f01a6b4 | |||
| 5e8eff074d | |||
| db028f2774 | |||
| a82a154be9 | |||
| af01927807 | |||
| f60aac93ab | |||
| 4860bf3f19 | |||
| adf2af82b4 | |||
| 15ddc5f06c | |||
| 8d16563014 | |||
| 3559b539e3 | |||
| da765a5eec | |||
| c2e8b5a1fa | |||
| 72c4962e97 | |||
| 789cf1d66b | |||
| 64ec922d7f | |||
| 85b3aefd67 | |||
| af0dabec99 | |||
| de85983247 | |||
| 7eaae3a6d5 | |||
| 403b57c076 | |||
| dd434b89d2 | |||
| 1a3d58e09b | |||
| 89ae239743 | |||
| c785d1509b | |||
| 9e412555bb | |||
| 0717805773 | |||
| d045c5a390 | |||
| 3cc0d0c735 | |||
| 9a3c727532 | |||
| a7f2484d45 | |||
| 96d97699a0 | |||
| e92e832258 | |||
| 3a769549d8 | |||
| 0eab0dc680 | |||
| 2b48f50de4 | |||
| fa60eacfc5 | |||
| d2a4136d4f | |||
| 7d88a746ea | |||
| 7f4537bdc6 | |||
| d68829820b | |||
| 9cf3036ab5 | |||
| 2467eb71c1 | |||
| 345bb5d1aa | |||
| 8d50828998 | |||
| 201de82baf | |||
| 99519ac3da | |||
| a575ab7c74 | |||
| c4f79814df | |||
| 6135f6271c | |||
| 8ef70f07f0 | |||
| 17b7e37885 | |||
| 35c17044e1 | |||
| 7085d98f41 | |||
| ee73e32b0e | |||
| 371430c172 | |||
| 495753b517 | |||
| 211be0a863 | |||
| 12c9a8e6c3 | |||
| fb5d9e0c01 | |||
| 61a2d962c0 | |||
| 440622830a | |||
| 2652990432 | |||
| 652e2f27b6 | |||
| 77a82eaa6a | |||
| 624a181b23 | |||
| 865ac52442 | |||
| 4f064d7c02 | |||
| facb67e94e | |||
| 124c838e06 | |||
| 026e894e1d | |||
| 2ed0f1661a | |||
| 00f285cba3 | |||
| ddf5bf472f | |||
| 534c7799e5 | |||
| b254aaa081 | |||
| 76f2860c74 | |||
| 5ebcb77d0d | |||
| 4847752ef4 | |||
| 84ec8d61ae | |||
| 0f13551b6d | |||
| 3e66c6cce4 | |||
| 09de3a5e7a | |||
| 00483d4c0d | |||
| 1e3d10ad31 | |||
| dc31cd7103 | |||
| cffb670f72 | |||
| 781fea7431 | |||
| 78b0b7e01d | |||
| e96367cd4b | |||
| 30af3c7f8a | |||
| 264405827e | |||
| 083721bbc1 | |||
| 91ed04ff83 | |||
| cbbd4fd029 | |||
| f6bc7721a8 | |||
| 32ec9e82bf | |||
| 69a7a8a04e | |||
| ccb5194bb5 | |||
| 2d280edf0c | |||
| afe4817150 | |||
| 6754b3746e | |||
| 287f83f4d0 | |||
| bf518a961e | |||
| 4a55467eef | |||
| 56cf5249f9 | |||
| 17e8bc6949 | |||
| 02ede8020f | |||
| 54158a0340 | |||
| 7ce96a4e3d | |||
| 2067b70445 | |||
| d02658e0ba | |||
| 27e68ed6a9 | |||
| b3e0ac017f | |||
| 8bc437a84e | |||
| 11e5a94fc4 | |||
| c11941cbc1 | |||
| f792aea98e | |||
| 12e5937a91 | |||
| 60b9cd8789 | |||
| 41e4c80494 | |||
| bd2756c0bf | |||
| 1f3c4948c6 | |||
| 062f9a195c | |||
| a3e8af40b2 | |||
| 49f4773e81 | |||
| ee78385b4c | |||
| e99ccd0051 | |||
| cbc022524b | |||
| 34d9d042aa | |||
| 22f69a99e2 | |||
| 4ee5539e3d | |||
| 048636e894 | |||
| 5797ad2d5b | |||
| ba9a8d52cc | |||
| ee18a9dd6c | |||
| 517c2f456c | |||
| e8734daa4d | |||
| 1fd7c6e2f1 | |||
| bc638ea06e | |||
| 5b0ba79a35 | |||
| 173c7b2aec | |||
| fd37a9c660 | |||
| fc460554e7 | |||
| 73490903a3 | |||
| 964c0ac420 | |||
| f59ad1620a | |||
| 4797f18819 | |||
| b0d73a3314 | |||
| 562e60f964 | |||
| fde0fa673b | |||
| c93d5e7830 | |||
| e305b973b2 | |||
| 506d3611fd | |||
| 14b644777d | |||
| b9c23c75f4 | |||
| af60d03060 | |||
| adb66cae9d | |||
| aeaa0c5f8d | |||
| b009da4b47 | |||
| 8abd70bed8 | |||
| 91cd6c1954 | |||
| 7a702489d0 | |||
| d33331f650 | |||
| 8e3bd07c91 | |||
| ad55551819 | |||
| 1d38e50281 | |||
| cef0882e80 | |||
| 5a07c4917e | |||
| e498d091cd | |||
| 8ba30c5453 | |||
| 685e2eaff7 | |||
| 6ca8471c64 | |||
| e30f4652af | |||
| 9acb89ba8a | |||
| 9b9a775a41 | |||
| a6f11cdb31 | |||
| 777642ef55 | |||
| d1d7fd258f | |||
| 7e4635de26 | |||
| d7b2173066 | |||
| 55e9c8c9eb | |||
| c34e1d3c19 | |||
| f89b1ba303 | |||
| fc7b6dd0c6 | |||
| 1b5240a513 | |||
| 4bcf43c84b | |||
| b57abfd563 | |||
| bfc26fa407 | |||
| e7b435b47f | |||
| dd6842522f | |||
| f56d944870 | |||
| 772b79306d | |||
| 4ef2c6286b | |||
| a5f7c1b867 | |||
| 4d8ef2a008 | |||
| 8bc28d472f | |||
| 3753ab1b55 | |||
| babc600915 | |||
| b2f92e246e | |||
| 92f9ccce5c | |||
| 1a67ca897c | |||
| 0ace28b784 | |||
| bd06f0c713 | |||
| 4e5c88eb74 | |||
| 004ad15875 | |||
| 1c0a731ff6 | |||
| 9a5f42c251 | |||
| c8cdade884 | |||
| bbff66a041 | |||
| 6b6394ba97 | |||
| d11c6a20bf | |||
| 6c396e1d88 | |||
| bffd9bcb53 | |||
| 7cee448d68 | |||
| c273bf6a7b | |||
| 047a13a8dc | |||
| 717aed5a06 | |||
| 7d58090e59 | |||
| 501df8cfb9 | |||
| 7f6fe09a00 | |||
| d183d579cf | |||
| bfa2fd2edc | |||
| 7c257a09f6 | |||
| da4111579d | |||
| 6b117234bc | |||
| c4bac660cf | |||
| ee2e7d509c | |||
| 461e93fc56 | |||
| c74adc6521 | |||
| 7cc60d0b0c | |||
| d8f0612f5a | |||
| cd4b41a537 | |||
| fdb2ee2847 | |||
| 9c4cc5acda | |||
| f901254519 | |||
| 18032bb9af | |||
| a7a5fe36f9 | |||
| 32e1536955 | |||
| 77c2ee6782 | |||
| dbe5b78307 | |||
| 9578fe03b9 | |||
| ef48b66ac4 | |||
| b9d586c009 | |||
| 1d51982cb0 | |||
| 046985277d | |||
| d679337700 | |||
| 2d5f896069 | |||
| de51beebe8 | |||
| 80b25657bc | |||
| 0db60348aa | |||
| 5017024557 | |||
| 94863d69b1 | |||
| 06466b060f | |||
| 3ac9f3d9cc | |||
| d335a0221d | |||
| a118d73871 | |||
| 6c13d87a00 | |||
| 9e2264c841 | |||
| c0248069a1 | |||
| 5ba4c10a18 | |||
| 82ceb71bd0 | |||
| a4636fd88d | |||
| e19e25473c | |||
| bde415edd7 | |||
| 2004090ce5 | |||
| 18ea542cc4 | |||
| 11a856fbb3 | |||
| 1ed7899296 | |||
| a79a40b1e8 | |||
| d4075a1ef5 | |||
| 99f3b7ae99 | |||
| fcb5b355b1 | |||
| 43d26af34d | |||
| 5e1c67c042 | |||
| 11ef2be506 | |||
| 0f9bb7793c | |||
| decd7c2f60 | |||
| edf88ffdf6 | |||
| 435a7c809b | |||
| d79c66e5b6 | |||
| 10a8520805 | |||
| cf6c16102b | |||
| 32baaea5cb | |||
| 27e2795576 | |||
| c21f3810b9 | |||
| 877e7ab940 | |||
| 7a9a871be3 | |||
| de31ce1c73 | |||
| 8b6dba8301 | |||
| af859b4c13 | |||
| 9b5295ff00 | |||
| c1a94d704e | |||
| c2b56878fc | |||
| 4757bd89c0 | |||
| 1e56bf939d | |||
| dbd5ae46dd | |||
| 7c6095b6e8 | |||
| 04888646e7 | |||
| f6ed3fbb76 | |||
| 7bf2918438 | |||
| 92fefc7089 | |||
| e6df4d977d | |||
| 62ca787e6e | |||
| 32d59fff61 | |||
| 1949b6fe0f | |||
| 95a5b5025a | |||
| aa22fd2ff2 | |||
| 50df9a70c9 | |||
| 6d88e150d0 | |||
| b1817e513b | |||
| ce737a9491 | |||
| 6ff4dce62a | |||
| 89b5582d0d | |||
| 09c5e8a375 | |||
| a1a7dcd6b8 | |||
| d223d872fb | |||
| 91eaa32ad7 | |||
| 6cdccf4353 | |||
| ac9aee97fd | |||
| 5be95be9ae | |||
| e402f5dfce | |||
| 61be113714 | |||
| a637f43edd | |||
| 4bb43887a4 | |||
| 802b20be6f | |||
| 216a9c3666 | |||
| d52b2a9adc | |||
| 81782c3927 | |||
| 2c2ebbba0e | |||
| 3d323a734d | |||
| 93263a61b1 | |||
| 8b551e5285 | |||
| e11c91ddd9 | |||
| 938c83533b | |||
| 46136d616f | |||
| 8fe902e96c | |||
| 2fb7dddffb | |||
| 5d1876ab6d | |||
| 1aa4e7eee6 | |||
| 995e12bd57 | |||
| 349b6e8254 | |||
| ee6dbb9ac7 | |||
| 5b85cd83f2 | |||
| 1645c3f66b | |||
| 084d45141d | |||
| 50bec7a461 | |||
| f80afddd8f | |||
| 5d2c630b05 | |||
| f655b2313c | |||
| 2a819c2849 | |||
| 0ef13dcf7a | |||
| 5e5f3c1e95 | |||
| c76ca2dd6e | |||
| ab490b8f95 | |||
| bd42d9e7cc | |||
| e3d8f4a223 | |||
| 34567e1282 | |||
| acfb14a1f5 | |||
| 6a3495819a | |||
| bf6e8d3c1f | |||
| 66f08cc1a3 | |||
| 470012501b | |||
| 986bd02e5e | |||
| 9b8510ab3e | |||
| 0db9710e0f | |||
| 7f231057fd | |||
| bb687e47cc | |||
| 0f3928ec9a | |||
| a8380334df | |||
| 70bead1eb1 | |||
| df63530b89 | |||
| 34dedd36e6 | |||
| eb6c15caba | |||
| 39a7815f80 | |||
| 4bbe367aab | |||
| 7d50c7e4fe | |||
| 5d0adb1783 | |||
| 81ef4bdee8 | |||
| 2cf365d36d | |||
| 22d8ecffe5 | |||
| b987331b4f | |||
| eff8159d46 | |||
| f0e4f4dc9d | |||
| e02a70249e | |||
| 899afd625a | |||
| 863ec08681 | |||
| 28c958fb20 | |||
| 4c9f4a55d5 | |||
| a7fcf77251 | |||
| a57745ed64 | |||
| dd16c7d560 | |||
| 7f3780a20d | |||
| 99c8713e7f | |||
| 49eb2c426d | |||
| 4c55ff5df8 | |||
| 714f8dea1d | |||
| 1419a919aa | |||
| 6d4717fc96 | |||
| 6a8f4caee3 | |||
| dbf96a69d7 | |||
| 0519f18bd7 | |||
| f7765c80b8 | |||
| f2e2ffa170 | |||
| b2a816452d | |||
| 299e9a85f2 | |||
| ad34863bd6 | |||
| 129a91b36f | |||
| 78f10de8cd | |||
| 189b2e5cd6 | |||
| d4f67ec3b5 | |||
| 7ec54b9c2e | |||
| 60d20ea998 | |||
| e80a73cc1c | |||
| 6e51a08694 | |||
| 0da6f6b4a4 | |||
| ba3e75e710 | |||
| 8fee5e0de7 | |||
| 68a060b7eb | |||
| 9f5be974b6 | |||
| ea976d5f08 | |||
| 892d68e792 | |||
| 5a0744e2f1 | |||
| c01d8199f9 | |||
| df023d6bdb | |||
| 4bfb562477 | |||
| 4bc01b92bd | |||
| ee0f4e11ea | |||
| 1aa780f0a2 | |||
| cf58f3cbf2 | |||
| 18619e9010 | |||
| ae37dce0f3 | |||
| e48831d092 | |||
| 99f25ef744 | |||
| acf6e86c0f | |||
| 19192b622b | |||
| 183f399341 | |||
| 240c1efab9 | |||
| 8bbdb0f1b8 | |||
| ecee135a63 | |||
| 51d4630405 | |||
| 60e7695546 | |||
| 6d14a858a3 | |||
| 08a6f3af36 | |||
| cc43202e8f | |||
| 8fb3f3b1c9 | |||
| 2fe2ff474c | |||
| f0ad851aa7 | |||
| ab29a712c0 | |||
| 8dd264c4da | |||
| 40282ae23a | |||
| ed75369c6d | |||
| b34f4141a2 | |||
| 5d5d8f073a | |||
| f690961af2 | |||
| 12aa43ff5f | |||
| 4f171e3eb5 | |||
| 671f5c3a68 | |||
| 1f12185441 | |||
| a3e599e38d | |||
| 5a3779e431 | |||
| 5ddcdef1b4 | |||
| 7b6b44b284 | |||
| a691d5c7e8 | |||
| 7cf40b16df | |||
| ad6b707abf | |||
| 133052b58c | |||
| 226bf7e705 | |||
| cdcbdc308c | |||
| 5bfa6151ac | |||
| 020760f0c8 | |||
| 0c4750547a | |||
| 9c46509f84 | |||
| 928a2d646b | |||
| 7ffd1fc9c2 | |||
| 6d4f456826 | |||
| e78bf87377 | |||
| c76fc5b909 | |||
| eecd14f53a | |||
| ef29b4a5b0 | |||
| d6748792e9 | |||
| ae9c26504d | |||
| 7f7b543e18 | |||
| 2464d7bd9a | |||
| 3ce71999e2 | |||
| 7f9d83c088 | |||
| e8f6e7b56c | |||
| 94c0957e11 | |||
| b0ffe03c99 | |||
| 8ea878a2a2 | |||
| bbbab914d8 | |||
| 735a45b4e9 | |||
| a4558302f2 | |||
| d8ba26f790 | |||
| dcc3055dec | |||
| 6db7116db9 | |||
| 422988b3f6 | |||
| 2f04c5fec8 | |||
| e811aa44b0 | |||
| 4c7ab232d5 | |||
| fc42641469 | |||
| b71cfce105 | |||
| be55c1ad6f | |||
| 979a846298 | |||
| a4c59ce964 | |||
| 208c70f933 | |||
| 9dcbc06b3d | |||
| e3f6da382d | |||
| cc201ce4e7 | |||
| 08bdd11410 | |||
| bac192d825 | |||
| 55c968f138 | |||
| 6df2bc2790 | |||
| f8576c7135 | |||
| 7d220f571d | |||
| eda1ebe36b | |||
| ae4288719f | |||
| a016b655f4 | |||
| f4bc2e0649 | |||
| cf6f7035b6 | |||
| cb7498a30d | |||
| ccb3cadd2a | |||
| 0fb1a0ed6b | |||
| 94e79f1e4c | |||
| 65a28e76e5 | |||
| 0c5a9172ab | |||
| 1c21a0d609 | |||
| 16d18552f8 | |||
| 001cb80cfe | |||
| bd14d9c07b | |||
| 08bbde327f | |||
| 12488bf2b0 | |||
| 4bf0d69f79 | |||
| 78e3b69cc5 | |||
| 531a38bc39 | |||
| 77fa5454e2 | |||
| 0cd382a1ce | |||
| 9fc0c98722 | |||
| af23074820 | |||
| fdf2d5b20b | |||
| b37f2141a1 | |||
| 520dc80eeb | |||
| 878fa48afa | |||
| 514cd1bd37 | |||
| f5ee5ea814 | |||
| e3b0f7cd94 | |||
| 5567038cec | |||
| 0327c9101e | |||
| 3d86d5f530 | |||
| 073724a84c | |||
| 6a129bfe92 | |||
| 53a4c36aab | |||
| eb36f4eca0 | |||
| 54838d386d | |||
| 0235821f24 | |||
| efd116ec52 | |||
| ff0f1c5c50 | |||
| 6bbb26d2ea | |||
| 2a1140c0b3 | |||
| a80c7ada27 | |||
| 9bc6d0c7d1 | |||
| f3566a4933 | |||
| cd958a6c68 | |||
| 4f6a920f72 | |||
| b717cf1dc0 | |||
| 33e5a51a28 | |||
| ff751ca423 | |||
| 93df7f4367 | |||
| dca5a7ce4d | |||
| bf4dd78a7d | |||
| 489e484117 | |||
| 6e1cc8449b | |||
| 148ad8032f | |||
| 6d53594850 | |||
| ee7a3b3686 | |||
| 18188516ec | |||
| bcc2f089be | |||
| 07843c00d3 | |||
| de12915eba | |||
| 4395718e0c | |||
| 913fdf5247 | |||
| 650c1730c9 | |||
| fba1c66499 | |||
| 1c04823877 | |||
| 6c84624d71 | |||
| 69fa9e7b10 | |||
| 350237a774 | |||
| b73ea55bbd | |||
| 9eac6a1db0 | |||
| ea6ab46a13 | |||
| 5f84865365 | |||
| 5b3c41bd77 | |||
| c6b7ff6c75 | |||
| 337a107168 | |||
| a7485cc7f5 | |||
| 8b4edae358 | |||
| b6dca5e9b1 | |||
| 371f0a6a73 | |||
| b777a2d3c8 | |||
| bdfc4636f0 | |||
| 7ba128db71 | |||
| 0f1d8478ce | |||
| 9eae2ad76b | |||
| f43f2956f5 | |||
| 2dc03cc537 | |||
| 233b0d0de2 | |||
| dc9a044141 | |||
| 518fba759f | |||
| 7dfa1ec984 | |||
| da5a538f89 | |||
| a518796736 | |||
| 13111b3779 | |||
| 8412d77067 | |||
| fe0ea168f3 | |||
| af9d97d561 | |||
| 478f5b6e20 | |||
| c89b125b9a | |||
| a981dc71f9 | |||
| 331dd49326 | |||
| b69c37f1bb | |||
| 20ef846c38 | |||
| cd9f00300c | |||
| d6e5b57a08 | |||
| d5e5d81ee2 | |||
| dee24e6f08 | |||
| 9a2a54b885 | |||
| 4c2b01ccb0 | |||
| ddf4136022 | |||
| 4f8fc61689 | |||
| c8a7a050de | |||
| fb04b3d78b | |||
| 0f28b59c5f | |||
| e2795341d9 | |||
| 04c20b84ad | |||
| 04f5d7e411 | |||
| 82877dc53e | |||
| c7eb22021f | |||
| 654fa0426b | |||
| ae6c1c0c66 | |||
| b3f5939689 | |||
| 184404beac | |||
| 456b8258c3 | |||
| a1896d189c | |||
| e47dde9f41 | |||
| 4be19ba6d8 | |||
| 73a2839e34 | |||
| 224472c90a | |||
| d77be82a99 | |||
| 4320c7b9fb | |||
| 2dcf7fb3dd | |||
| cd1913c008 | |||
| 62694e4a93 | |||
| e92fbadc3a | |||
| 17c10bbe68 | |||
| 6c548f025e | |||
| cc15882faf | |||
| 3fd745a5df | |||
| 5e968e0aa8 | |||
| 1e3783b4dc | |||
| c355e02a20 | |||
| e178dca167 | |||
| 8beee23e21 | |||
| a894d377dc | |||
| f41426c85a | |||
| 41877e362a | |||
| de32b02c75 | |||
| e3cba22ab7 | |||
| 25bcc3cbc1 | |||
| ca5310025f | |||
| 5b9561c13e | |||
| d594ac2f00 | |||
| 5157089d87 | |||
| d5b455b1f9 | |||
| 6cb1ed6c92 | |||
| 3d0d52f82a | |||
| be04828d35 | |||
| 5f9aa2edc0 | |||
| a5751895f0 | |||
| 78b0918216 | |||
| 5a7ed24078 | |||
| 509f8f6a95 | |||
| 6f3301e82f | |||
| 80f11ce30b | |||
| 95a6d24111 | |||
| 1fc2c511af | |||
| 3bcaac7051 | |||
| 25afd5c0e7 | |||
| dbbbeddad0 | |||
| c0f274d54b | |||
| 7816e078b5 | |||
| 56bda82529 | |||
| 54adc34348 | |||
| a4ed700338 | |||
| e2d107a70b | |||
| 31f080e4f4 | |||
| 6e4b9af6b1 | |||
| d301d2a06b | |||
| 2bbd4cbb17 | |||
| 5a2d39320f | |||
| 91158b1c20 | |||
| 06115f25ba | |||
| b3b533db94 | |||
| e16125cb50 | |||
| eb0dbac0c1 | |||
| eb1d1876d3 | |||
| f751b1b7ff | |||
| 34f9cfaa02 | |||
| 6dba32bf99 | |||
| 9529246bfb | |||
| 25774ee4c3 | |||
| 1137513236 | |||
| c76855698e | |||
| be8c66adc9 | |||
| be4a374122 | |||
| d76a6d1c38 | |||
| 5945196a4f | |||
| e164ea4b46 | |||
| db3dca1d73 | |||
| eea30fa253 | |||
| b585a0ef61 | |||
| db82f22320 | |||
| 66ce38d948 | |||
| e61d435b00 | |||
| d0a8985800 | |||
| 4c1c092234 | |||
| f02079dafe | |||
| 4be0093a8a | |||
| 130eb778d3 | |||
| be177e0f80 | |||
| 42f54b8df9 | |||
| 4b60b05f75 | |||
| 6afd0f9f82 | |||
| 8288e85c25 | |||
| bb2f4ff16b | |||
| 682ba1f764 | |||
| e0c679f5ee | |||
| a1d0d028b6 | |||
| 7741872578 | |||
| d1dcd536f5 | |||
| 177d380092 | |||
| 33a15f1e93 | |||
| ad2eaf7aef | |||
| 23ae99b97e | |||
| 3c37de152d | |||
| 2dd99d053a | |||
| c60d66d94a | |||
| 6b814b8dca | |||
| 11c71d7a5d | |||
| d90b2e6142 | |||
| 2ab7f3c767 | |||
| a937fa0ef8 | |||
| bc36749f6d | |||
| 88d1735380 | |||
| 92672ffddf | |||
| 2ccfa9b4fa | |||
| 1f07be6ae0 | |||
| 9a8c7b290f | |||
| 2e3bc15d2b | |||
| 9f0117d914 | |||
| 5e5412887c | |||
| b2efd5150b | |||
| 50ec31a7a3 | |||
| 20bd9d6160 | |||
| 8c3c07acb7 | |||
| 26a56c3105 | |||
| d0070c72fd | |||
| 780f3c49e9 | |||
| 2c191dbdbf | |||
| 4b617f96a3 | |||
| dabc3f998b | |||
| 23a22102c5 | |||
| 8d9ff7af11 | |||
| fdcb6086d1 | |||
| 00e05efd7c | |||
| 0dd5eef3f2 | |||
| 6ecd30d42b | |||
| 317091639f | |||
| 9c8e879465 | |||
| dc5a04346a | |||
| 44b533f501 | |||
| 0fa459d590 | |||
| 96d34bb5ee | |||
| 9f712b44f3 | |||
| 1ff8663e44 | |||
| 52f042263b | |||
| da7e57989c | |||
| 65c3d90642 | |||
| 3c044d729d | |||
| 82ecf894c0 | |||
| 7b15f7d74b | |||
| 371406845c | |||
| ccd26a6d42 | |||
| e992930ff6 | |||
| f66d8bed8f | |||
| 155634ef34 | |||
| dbc7bc4253 | |||
| fc427e618a | |||
| 6d66190644 | |||
| 9b2da0d645 | |||
| 95c60b9554 | |||
| bc7f6a6fac | |||
| 0b1118540a | |||
| 96bd0bb46c | |||
| 33e97ee49b | |||
| 8414facde2 | |||
| 2a0d5a0a03 | |||
| aec30301a1 | |||
| 9cf246a03e | |||
| c385035ac5 | |||
| 409cf2c630 | |||
| 02ddbc8381 | |||
| 1c2a588864 | |||
| de043eeaa2 | |||
| 5e5f23b5e5 | |||
| d671ccd6ba | |||
| f4f2f09d17 | |||
| 2f1c70e49f | |||
| d9890498d1 | |||
| 46ae505bab | |||
| b0e84a68d0 | |||
| 356a5b6136 | |||
| e86193cebe | |||
| e35b2ec3ff | |||
| 69d421d785 | |||
| 47c51b28c1 | |||
| dd2653968e | |||
| b091d95eb2 | |||
| 33327d3992 | |||
| 027ce58655 | |||
| cd611ef4bf | |||
| bc7f5118ea | |||
| 53ae915044 | |||
| a47f14ec13 | |||
| 86149ba3a7 | |||
| cc3822b222 | |||
| 57b9602b13 | |||
| c9839dbefa | |||
| 5b6423ec6c | |||
| b3efcf9b68 | |||
| cadb0f96e2 | |||
| d3b825b49f | |||
| c808cbb4fa | |||
| 228d3af1fa | |||
| a1df325051 | |||
| 8e6fdfac3c | |||
| 9a1afb2376 | |||
| e9ab8c4dac | |||
| 1d98acc407 | |||
| 034613b50c | |||
| 282e611ef7 | |||
| 49fc903334 | |||
| 44b6157f17 | |||
| 0a8d3f9251 | |||
| ac505ede44 | |||
| 4770f8b580 | |||
| 67e5598d28 | |||
| 554d7ab887 | |||
| 40734bf90e | |||
| 3e720f8bae | |||
| 66d9c79bef | |||
| 89a5e5d57a | |||
| 8f6b0c50d6 | |||
| d85dfaf38a | |||
| 8511152982 | |||
| 40f9a51d4f | |||
| 30ad6d93bc | |||
| 770d907fb8 | |||
| 46cdbacf0b | |||
| c0a8adc167 | |||
| 4dd176a7f2 | |||
| eac9023b9a | |||
| a4c403286d | |||
| 3a2ee0fc72 | |||
| f097fb57b5 | |||
| 7415a362c4 | |||
| 8a7b7f5c9b | |||
| 4ce35ef352 | |||
| a12f601b9c | |||
| 4106161aa8 | |||
| 58c2f35bcf | |||
| c41839a816 | |||
| df729cd0f6 | |||
| 230ab34fe9 | |||
| 51fabab7b7 | |||
| c7a13a4641 | |||
| f855386bf1 | |||
| b8d1d9d7f1 | |||
| a22412d39d | |||
| f8bc9ba476 | |||
| fe83937368 | |||
| 3def6265c4 | |||
| d9f7c19344 | |||
| db1dd618ea | |||
| 132306fef1 | |||
| 18d29a0c7c | |||
| 4125fa75dd | |||
| bad7772b15 | |||
| 6a23202e89 | |||
| 21c384fcdd | |||
| b140fddebd | |||
| 24ea1c4847 | |||
| 9d115fc02e | |||
| 5e7756810d | |||
| c65abd19ae | |||
| 1a07c39fad | |||
| ee23cb2185 | |||
| ee5617c6b8 | |||
| dc757cbf6c | |||
| 3d3ec2a194 | |||
| d2e79f33a3 | |||
| 6156228c89 | |||
| 90f7e370f3 | |||
| 92688f03a8 | |||
| 80d0d6ecc8 | |||
| d29df4289e | |||
| 84406f0823 | |||
| 380907af8d | |||
| 0e308d9f50 | |||
| 7805f3f85b | |||
| e04d13323d | |||
| 6e8bfe1ea6 | |||
| 3baceb9dc4 | |||
| abf8ca2dc7 | |||
| 2a0a5f2d08 | |||
| d45b228461 | |||
| 231e11715f | |||
| d6f1120dfc | |||
| 7471bc791c | |||
| effcffff8a | |||
| 76186cab97 | |||
| 4756e04e25 | |||
| 5b73f1e56c | |||
| af7d332453 | |||
| 5439c3a3ce | |||
| 6c4b6bbfbe | |||
| 53719e5a8e | |||
| aed34c3b9b | |||
| a5482453ce | |||
| 712d2011c3 | |||
| 0e6942a182 | |||
| ce169edd08 | |||
| dd526e00ab | |||
| bad2ef63c6 | |||
| e283c6557b | |||
| e8da23c3e7 | |||
| 08d7bee224 | |||
| 16c95c6deb | |||
| 1d03e97721 | |||
| 9abcba3753 | |||
| b501c9bf4b | |||
| 72c506b62b | |||
| f09dfb7035 | |||
| 6cca763284 | |||
| 915c41c9d9 | |||
| 9c2c548874 | |||
| fdf699bf35 | |||
| e3ce1ab1d1 | |||
| af56d6f265 | |||
| 05eb687ca4 | |||
| 99e4408da4 | |||
| 64dd69f550 | |||
| 8b8de6bcd3 | |||
| b920ee8550 | |||
| 89cd67792b | |||
| 1f7ecb969c | |||
| d4ef1761e4 | |||
| dc01cc5c8e | |||
| db341f1814 | |||
| 06e469f059 | |||
| 9ec1e674d0 | |||
| 5c54722626 | |||
| 0a92b13263 | |||
| 2fbc3c954a | |||
| 746f96cdcd | |||
| ee9d78b190 | |||
| 0e6a02b810 | |||
| 864dddb1ff | |||
| 321495f253 | |||
| eced31e3d7 | |||
| 4b8dc06ddb | |||
| ff3ba18b15 | |||
| d24f327342 | |||
| d801a2789e | |||
| b8c8c49176 | |||
| 601f24a006 | |||
| 160b2bf03a | |||
| 944163e889 | |||
| 8656fe002a | |||
| d5e50983d8 | |||
| f3d31a62db | |||
| ee15b2c166 | |||
| 4d84ab155a | |||
| accc063db8 | |||
| b88d26ce77 | |||
| 886386508c | |||
| d893034f47 | |||
| f4b798765d | |||
| 5e6a9da3ed | |||
| 10f214fbb4 | |||
| 698d583d1d | |||
| 598211c349 | |||
| 7843821109 | |||
| 96f3baca41 | |||
| d1980ef978 | |||
| 67b4157e25 | |||
| a523903c15 | |||
| 92e9fa2084 | |||
| c75e1df190 | |||
| 79bf45b823 | |||
| 58989465f4 | |||
| 1e6b442c6c | |||
| 33addf4449 | |||
| c5fed9524a | |||
| cbfadde43c | |||
| cebe1eedeb | |||
| c22a9e51a1 | |||
| e41022c7be | |||
| 56a9389023 | |||
| 1188230641 | |||
| e760b42560 | |||
| 627c03193a | |||
| 0f837f3438 | |||
| af072da0b0 | |||
| c4f3b93da5 | |||
| 906f11ed76 | |||
| 2e7329931c | |||
| 5e5e1850ac | |||
| 93d16a27c1 | |||
| a602309a02 | |||
| 6b250d1ab6 | |||
| 1ee6affcb3 | |||
| 11e9eb3aa3 | |||
| 7a1dd0db29 | |||
| e41918569b | |||
| ec6f75b59e | |||
| ec595c23e5 | |||
| 2c5a37d38e | |||
| 3ec61cd012 | |||
| a3b4b9c8b2 | |||
| b3db49b4ae | |||
| 5166d16406 | |||
| 3e7dd9bb77 | |||
| 0ab57b3d76 | |||
| 0be0824207 | |||
| 7def4e8e73 | |||
| 2397c78e9f | |||
| 9a59df793d | |||
| 1852ba99b3 | |||
| 0d665c661f | |||
| f11828075b | |||
| 9a1efefbd4 | |||
| 066ff96b58 | |||
| 7d8b00d1b9 | |||
| 5d4f3182fc | |||
| b8d80f5285 | |||
| ccb9df2a08 | |||
| c3ae9e1ee2 | |||
| abcc4b6739 | |||
| dd3f65496a | |||
| 2d69fc39de | |||
| 731cac4262 | |||
| b4846bd5d5 | |||
| fac39344f4 | |||
| ffb9878893 | |||
| 034a1af649 | |||
| 06fd894f79 | |||
| 5731648479 | |||
| 1ebc2cb9c1 | |||
| 0bd76ef7a4 | |||
| ea15f7746d | |||
| ed102269e7 | |||
| 76e1f4720b | |||
| 2317b77314 | |||
| 1a7bb10a22 | |||
| 0732006d5a | |||
| fb2e12089f | |||
| 7a0e03b374 | |||
| f2235abf08 | |||
| 5435ce20a9 | |||
| 124f1fe701 | |||
| 37e2c18c3c | |||
| 032f5a5dab | |||
| 7e41a2f40d | |||
| 8b90eb37c5 | |||
| ff797b11d1 | |||
| 31c665a837 | |||
| 68c39697a6 | |||
| 6f8881b610 | |||
| 1b468ba5d8 | |||
| 7aca2b1584 | |||
| 41e56b1f2e | |||
| cad96e652f | |||
| c7bde0ff19 | |||
| 6b94bbac2d | |||
| f7de9fbea4 | |||
| 5465479e57 | |||
| cd3ce86dbb | |||
| b109025fac | |||
| 6e74411a8e | |||
| 6c51982793 | |||
| 8f841cdea4 | |||
| eab4cfdf2d | |||
| 34c0361d1a | |||
| 24c27737c1 | |||
| b0dabaafe8 | |||
| 9472c0c5e5 | |||
| 89fe3c9150 | |||
| 9e1d551173 | |||
| 2d61b413d6 | |||
| aec08c74e0 | |||
| 48e8cb5eb1 | |||
| fd947ab887 | |||
| 5395b41852 | |||
| b7536f129b | |||
| 28b026c9ad | |||
| d4b7bfbe1d | |||
| 4b2ce036e8 | |||
| 2a350df5eb | |||
| bdc815066e | |||
| 44f4f22fdd | |||
| 5ae2044d02 | |||
| 5e80a05f32 | |||
| eb7534d319 | |||
| 471b09bd6c | |||
| a4549cbfa2 | |||
| d663267cde | |||
| 35a56962fc | |||
| 82161e60bc | |||
| 51a47cb2b1 | |||
| 9804debe86 | |||
| c93e2b80ca | |||
| 1555876280 | |||
| 1d08e6619b | |||
| 0880487be2 | |||
| 2ac4ffc576 | |||
| 7b2a0a92c4 | |||
| d883274586 | |||
| 803de95367 | |||
| 3ca39728d8 | |||
| 1111000217 | |||
| dd505fedcc | |||
| 48ff2fb8b8 | |||
| d5eafad48e | |||
| 2e1c86c0c7 | |||
| c728bf52b8 | |||
| 95a26f5080 | |||
| 85eaef6aa9 | |||
| dee160f2b8 | |||
| 6d38e52321 | |||
| caed94328f | |||
| ebf92d3033 | |||
| fdadfa3a80 | |||
| f8b84185ac | |||
| caf86686dd | |||
| bcd5d9ef90 | |||
| 45b5922d01 | |||
| 1a91eacdcb | |||
| 0421fe9a82 | |||
| 43a213643b | |||
| cd8939fe0b | |||
| c250d7c073 | |||
| 3b570edea1 | |||
| 199a3306db | |||
| 3236e06fb9 | |||
| 492618ae67 | |||
| c5737db4f5 | |||
| 40b49b9873 | |||
| 1fa34574e8 | |||
| 4c2db68037 | |||
| 1c522159df | |||
| 967dca7912 | |||
| 7d66c502f4 | |||
| 9b9e2fe6cd | |||
| 47ee0a4c97 | |||
| f10bda463c | |||
| 72d336265b | |||
| a087a6694b | |||
| 5eaf6b2adc | |||
| 57840a37d0 | |||
| aedcb372f6 | |||
| 7f554d3c84 | |||
| edf1daa7d7 | |||
| f554bf925e | |||
| 9676309ba2 | |||
| c78444fc24 | |||
| 4ab51d4bfa | |||
| e381c13dc6 | |||
| ec31898f25 | |||
| a88d78a2e9 | |||
| 92430afba9 | |||
| 8f60a4df8d | |||
| 08c9e627ab | |||
| c092d3cab4 | |||
| 46ad076751 | |||
| 07731614a9 | |||
| d8ffd729f4 | |||
| b23d94eeb8 | |||
| 4ed7144ca4 | |||
| ad924e8cc9 | |||
| aa929ec24f | |||
| 07f7fd3c7a | |||
| 83beca098b | |||
| 2c3d35d249 | |||
| 90e655d979 | |||
| 8204b51213 | |||
| c3f40d0555 | |||
| cbd134987b | |||
| 167fd68774 | |||
| 2b8cc7cfde | |||
| 62280fb24b | |||
| 2a7604ef5f | |||
| 0b47aafd14 | |||
| 24eefbed2b | |||
| ab7a73c879 | |||
| 81e0868725 | |||
| eba1e366bb | |||
| e9ccdef447 | |||
| bdce27dd7b | |||
| 436ab89d2d | |||
| 74c2db4909 | |||
| e12c3f332e | |||
| 34a64db91d | |||
| e2a4a1e2ea | |||
| 22f12316ef | |||
| e24acece49 | |||
| dd7462bd3f | |||
| da7e0cba3e | |||
| 50219aa872 | |||
| 000660b43a | |||
| fbeaa59f18 | |||
| 578e601368 | |||
| 247fe27f03 | |||
| ee2e807cc2 | |||
| c4a880c870 | |||
| 4eb6fac881 | |||
| 0ab37f49fa | |||
| 376ee02041 | |||
| c779dc6577 | |||
| ad71e81338 | |||
| 9f2ba09fc4 | |||
| 1e6cee2c5d | |||
| 4dc742489d | |||
| d751b985ac | |||
| 8a58190cce | |||
| 612ca15fc0 | |||
| 2200b76054 | |||
| 08771395b8 | |||
| e3c06cad57 | |||
| 4dfadeaf15 | |||
| af1896dc36 | |||
| 350ffdee25 | |||
| 281b92c262 | |||
| 75f1cf8cbb | |||
| bf0f44773f | |||
| dfb89ef7f5 | |||
| 5ef7126a3a | |||
| c9835a53e3 | |||
| 5ea48e6fcd | |||
| 1d1a703e3c | |||
| 8110fec4ef | |||
| 67ecf4e350 | |||
| e8ed0a3034 | |||
| add962c8ea | |||
| 9bed393210 | |||
| 3aac2b2895 | |||
| aa6814a6d3 | |||
| d291582ad9 | |||
| ebc591747a | |||
| 456602b79f | |||
| b1835a91af | |||
| 0a8d88a4fe | |||
| e2adcbb486 | |||
| aee13d295c | |||
| 6677e0e0a0 | |||
| 9d64914e62 | |||
| d136977fc4 | |||
| 7fb995094e | |||
| f002f66890 | |||
| 9de3ed8cf0 | |||
| 7ff843ec1a | |||
| b181788dc2 | |||
| 81302c1e9d | |||
| 77fbf3eb51 | |||
| 837c0c06ed | |||
| 93e7bc2a2e | |||
| 702ab3c504 | |||
| b9dea42be6 | |||
| ae608d4d78 | |||
| 5e8c88d657 | |||
| 9bbe0f9414 | |||
| f290748c72 | |||
| 96821f6303 | |||
| d290c6702a | |||
| 2877cb7160 | |||
| 14fd3c94b5 | |||
| f615a5d05e | |||
| 04a4357684 | |||
| a4c25321d8 | |||
| 068282af55 | |||
| 24078661c9 | |||
| 54670d4259 | |||
| bc276acb96 | |||
| 9e8869acf1 | |||
| c39f5e1483 | |||
| f41a09b68e | |||
| 4416fc919e | |||
| 5ed913ba5e | |||
| f4329a9483 | |||
| 24a4c31f0d | |||
| 2b1c4685d2 | |||
| 980a92c625 | |||
| 54923c082c | |||
| 7ce783705a | |||
| e23cf3377e | |||
| bed9beafdc | |||
| fe1b759787 | |||
| 8c6c81e8d0 | |||
| 874e94218c | |||
| 755a70bf77 | |||
| c58de34e63 | |||
| c798fe6822 | |||
| 5f4dfdd5d2 | |||
| 1f7043e02a | |||
| c651be7a12 | |||
| 0cc15102fb | |||
| 22aaefd1a0 | |||
| 8638626ff5 | |||
| 24fa5c8cbe | |||
| 90d054c2ec | |||
| 555145a650 | |||
| ec17d557a7 | |||
| 792df32e69 | |||
| adc96917fc | |||
| 9b0e35b4b1 | |||
| 9d652c8fe2 | |||
| 1be5794e05 | |||
| 0e561e1cd6 | |||
| 4475c38140 | |||
| cf02408620 | |||
| 87ab1d9ca4 | |||
| 9c317b8c3f | |||
| ea18b11475 | |||
| 17afa11723 | |||
| fc660e3486 | |||
| dbc12bb9ba | |||
| 2c1f58e773 | |||
| 2bde412fa3 | |||
| 03a9fc3419 | |||
| 2ca7324a45 | |||
| cf381880a5 | |||
| 12230f1fc9 | |||
| 6145214734 | |||
| 412801821f | |||
| c65c7ae252 | |||
| c3511005c7 | |||
| 31ea149820 | |||
| a0aa702725 | |||
| ac1e82075c | |||
| 65649ade14 | |||
| 34135f8e6b | |||
| 31c8a04856 | |||
| 234f9b202e | |||
| 4035c0bbe0 | |||
| 03a228fbe7 | |||
| 6e3de26477 | |||
| d892c57596 | |||
| 576ed7b7b3 | |||
| 966dede6e8 | |||
| af32590314 | |||
| 475eb8f263 | |||
| 8a40ac8991 | |||
| 3335bf21fa | |||
| 011f51fbd9 | |||
| 333714911c | |||
| f165423527 | |||
| 428fbb9cb9 | |||
| 342f9c60b2 | |||
| e13070cd6d | |||
| 76bb6bab96 | |||
| ff7b147888 | |||
| 55a598b796 | |||
| f63eac9a73 | |||
| 8d7c4cd108 | |||
| 99f608defb | |||
| 34596ada49 | |||
| 60c8f6f578 | |||
| 959da6c5ae | |||
| 5c127f945f | |||
| 74ec733444 | |||
| f560884436 | |||
| f68f82e3f4 | |||
| 56bd8006bc | |||
| ca062c3ce2 | |||
| 90aba32ca5 | |||
| e164a8274a | |||
| 23b25d4954 | |||
| bc7c8993c0 | |||
| 9db7de8373 | |||
| f8fddb49e2 | |||
| 991b2e7ca5 | |||
| 54cd96e5e0 | |||
| 599f91860a | |||
| d59564999c | |||
| 5a87adaa7f | |||
| 4e6150fe1e | |||
| 553125713d | |||
| 5583d9f315 | |||
| 20df4967a4 | |||
| 6a30435071 | |||
| 5776ff1fdf | |||
| bbb00816f1 | |||
| 3b1c409fd7 | |||
| ee68798de3 | |||
| 3ae8dc9bd7 | |||
| e9dca92c11 | |||
| 98cce223e9 | |||
| 1d7a470f78 | |||
| 461d5efc4b | |||
| 705dbf60fa | |||
| bb180ad59a | |||
| 463e1bcb90 | |||
| 22ac2df595 | |||
| 73af635be6 | |||
| c1c97a5fc1 | |||
| 6a97dc8825 | |||
| d832f34733 | |||
| 859a600b92 | |||
| 6b3cf50f38 | |||
| 3ccd1bc368 | |||
| 624d33b96f | |||
| 156f61f526 | |||
| fd3a04fce3 | |||
| 62be4e1274 | |||
| db096196c9 | |||
| a0ac70be3c | |||
| 1f0f89f83c | |||
| ee706ad8c7 | |||
| ce31ea8bf3 | |||
| dcab8e3ac2 | |||
| 1ad9a7e176 | |||
| f1bd7ab1dc | |||
| 79399913d7 | |||
| 4a2e88a81c | |||
| 8d5b748b09 | |||
| b2dba8af73 | |||
| c258bc49c3 | |||
| e3e2a354e7 | |||
| 32c1c31139 | |||
| b8b5a33833 | |||
| 5407fa73f8 | |||
| 1cb0c0071b | |||
| a456ac4c90 | |||
| 71b48427c5 | |||
| ec06a01b6c | |||
| e3ccc34a2c | |||
| 396721568f | |||
| e53ab85745 | |||
| 4d99b37def | |||
| 2e24da3dcd | |||
| 0cc1bd2dc6 | |||
| aec162c50e | |||
| d5e9340f8f | |||
| 6fe87c4c69 | |||
| 85f0a87213 | |||
| 853f85be2e | |||
| a7448e3a1d | |||
| 521e753183 | |||
| 9193941fd0 | |||
| f56c6effe4 | |||
| 4cfcb239c1 | |||
| a4be274718 | |||
| 120f861a27 | |||
| 7e56d85b83 | |||
| 20af495581 | |||
| bf94c48225 | |||
| 27a68333b1 | |||
| 63f18dd26a | |||
| 4ea787743e | |||
| 3a4b881576 | |||
| f087594331 | |||
| 5491e40fd1 | |||
| 4b690ec9ad | |||
| 9fecb03b5f | |||
| de6e3d46ec | |||
| 3006a26500 | |||
| 6ffed9387c | |||
| 558627e7a9 | |||
| 4b276f977c | |||
| 99fe4f615d | |||
| 928c306803 | |||
| a3eddf8ba7 | |||
| 78e0ae31af | |||
| 1a90ce0950 | |||
| 2465b3eb5a | |||
| 16a2e34e95 | |||
| 5c52d68091 | |||
| 1a2e180f4f | |||
| 9048053669 | |||
| 69b69714cb | |||
| 1ecd9f9e19 | |||
| 2bca9ca9ec | |||
| d66028ed0d | |||
| 1cf33044bc | |||
| 2c138c8355 | |||
| 73ffcb9bc1 | |||
| 730025e144 | |||
| 91aa1d718a | |||
| f881bfc4fc | |||
| e76c3fff69 | |||
| 9f168071ff | |||
| b6652b7619 | |||
| f6d501f69e | |||
| 4c052cb3b3 | |||
| ea8ccf38db | |||
| cf12ff8070 | |||
| b7a95244db | |||
| 4c884651a8 | |||
| e9eca577aa | |||
| cff78b477c | |||
| b232410d25 | |||
| 5ff338d4ac | |||
| a5ceea153d | |||
| f3544dc826 | |||
| b0bc68ae8a | |||
| c38e947dc6 | |||
| ec826fc8ce | |||
| e5c4f782a5 | |||
| a5ddebf44d | |||
| 38804898c5 | |||
| 2bd67f3519 | |||
| c8ed611c9c | |||
| 3d7d8caa82 | |||
| f64108523c | |||
| a7493504ed | |||
| bc5293b5a4 | |||
| c4bdc5b856 | |||
| b5b4023056 | |||
| 0e598cc51d | |||
| 9fd09924eb | |||
| 10d218089f | |||
| 1ba0d198a7 | |||
| c44132d29d | |||
| a018a2c07a | |||
| 266d2efde5 | |||
| 3b33b054d3 | |||
| 1140b51e91 | |||
| 9d25c8fcd4 | |||
| e8ade18d47 | |||
| ed243f4e3e | |||
| e0af4b7925 | |||
| 80e53adbd8 | |||
| 36a29357a3 | |||
| 5bb9aceaac | |||
| 02d893b316 | |||
| b1850e58f4 | |||
| f1e566dddc | |||
| 2f60da33b7 | |||
| b0456d155a | |||
| 5f57a48996 | |||
| bc9d137001 | |||
| 483946787a | |||
| b165f233a8 | |||
| 3b325b2482 | |||
| 2dd480a3a6 | |||
| df33ed40d6 | |||
| cf4d78c87c | |||
| 8007d0dd6a | |||
| d7098f77c2 | |||
| 514284e784 | |||
| 2a3029edb4 | |||
| 45a1ed69d4 | |||
| 7248d8d7ce | |||
| fa84401866 | |||
| 910b94c5fd | |||
| 40cbddab29 | |||
| 853cda4b80 | |||
| 91ec0ad077 | |||
| 4be2304ec1 | |||
| d0ee402939 | |||
| 2d095daddc | |||
| cf4fcf3351 | |||
| 42d57fb8c2 | |||
| ba13c1528f | |||
| 857fb3342a | |||
| 17189e3125 | |||
| d0209d945d | |||
| 1b6bfa1259 | |||
| 4ea813c983 | |||
| 71d2af07da | |||
| b36f8c701e | |||
| d64d3ef101 | |||
| 05fa4a92de | |||
| 990314cefc | |||
| 60d97ad9c9 | |||
| 6bfa31a89f | |||
| 8d8ac10429 | |||
| 56f398fb55 | |||
| cf5aed00e2 | |||
| de616dfdf0 | |||
| 3cf428d7ea | |||
| 29d93ba33e | |||
| 76c84c7615 | |||
| e129c29e2f | |||
| 52d325b446 | |||
| 74efd98699 | |||
| 28effaea36 | |||
| 6256549f44 | |||
| 2adec2fa7b | |||
| 32e816b713 | |||
| 6c7b113de5 | |||
| 1d5cce61ac | |||
| 85f91b9075 | |||
| aa64a0d3ce | |||
| e9d95a85b7 | |||
| 625c92a985 | |||
| 3cc9425219 | |||
| 0a86ccb142 | |||
| ce82e07dc9 | |||
| 048c60614c | |||
| 148fa6d151 | |||
| 088543176f | |||
| 536746d47e | |||
| c15cbad396 | |||
| d3baa58c7e | |||
| 7c885de6c7 | |||
| 010b8a382e | |||
| 314053af54 | |||
| 34a7f8a99c | |||
| 87031984d9 | |||
| 83687f96a5 | |||
| f33905ed80 | |||
| f91c4d586c | |||
| 77ec4adcad | |||
| b5a8186d99 | |||
| ed25e554e1 | |||
| a388ec71e3 | |||
| bde3c2e19d | |||
| d1d8d196ba | |||
| 7be5aebbc9 | |||
| d15fcb6b24 | |||
| b3ac38a6f1 | |||
| dae9dad2f7 | |||
| 603dc30bb1 | |||
| 71070da13e | |||
| 8fa1d4eb9b | |||
| 41f91f9cfb | |||
| 5699f3c6bc | |||
| 300babd6b1 | |||
| c1baca181c | |||
| 851fe9f72c | |||
| cf635cbdd9 | |||
| abbd8635dd | |||
| 2c2218bcb9 | |||
| bb6c06d3f7 | |||
| 90e22f179e | |||
| 0a00d1fbf3 | |||
| 6f0b8d1d7b | |||
| ef0d99340a | |||
| d4d388a94b | |||
| 7022ce7553 | |||
| 4a96122067 | |||
| 862ac3af8a | |||
| 333c2765fe | |||
| 89feb68b7c | |||
| 1b901673fc | |||
| fb60c244f6 | |||
| 3cea2df459 | |||
| 1cf514d1e6 | |||
| 65e18a8669 | |||
| 3e8f325ddc | |||
| 0d96c49f4a | |||
| bfc3fc1dec | |||
| 327f235af9 | |||
| df7fc0c4df | |||
| 33d9664df5 | |||
| 0d237028e7 | |||
| 80b9115393 | |||
| 606229a08f | |||
| 2ac17afe30 | |||
| 70f23e695b | |||
| 3084b0c41c | |||
| b75db9e473 | |||
| c89e9c5f73 | |||
| 61107b8577 | |||
| 35ff449dc3 | |||
| ae1f5b8b06 | |||
| c5bcae1e34 | |||
| e9ab6e7301 | |||
| a6ce2e691d | |||
| bfe04bdd15 | |||
| 2d0f9f01d5 | |||
| 87a967ad9c | |||
| 290b17a5f9 | |||
| 76572b990b | |||
| 54efb48d62 | |||
| 83bd780f2a | |||
| 2ba4ac6d20 | |||
| 98dc52f124 | |||
| fbb2f30f3f | |||
| 8ec3d18339 | |||
| 26779cbf4a | |||
| 4f429fb536 | |||
| 7e1706f700 | |||
| d491b29037 | |||
| cf9b60660d | |||
| a5e9ad9f19 | |||
| 6049a9fa0a | |||
| 5196ce5263 | |||
| 9231da4610 | |||
| 89f8030ba1 | |||
| 534f57b227 | |||
| 4d3ebf31d4 | |||
| d778c7922d | |||
| 5109c6f72b | |||
| 5005d32afd | |||
| 88be655dca | |||
| fe5789d747 | |||
| 00201b5f9c | |||
| 85f7acf9d5 | |||
| 44d1cdc2b2 | |||
| 90c2202f6e | |||
| d30574de24 | |||
| dec3748fe5 | |||
| e8cdff2310 | |||
| a0ca9d675f | |||
| baf410c712 | |||
| a81af2b449 | |||
| 678dde710b | |||
| 93a35d8fdc | |||
| 0878f44b09 | |||
| b89ae245ec | |||
| 536da01714 | |||
| a1b991aaeb | |||
| 7bee9a5829 | |||
| 17a90e3b00 | |||
| 43ba9b1172 | |||
| fdb01046e6 | |||
| 09421c9189 | |||
| c563204b0a | |||
| 33b3ee89f3 | |||
| 008b61c9f6 | |||
| 7546db4d42 | |||
| 925243969c | |||
| 7bce4a963e | |||
| 42d09a6d80 | |||
| b6334176e4 | |||
| 42a175bd53 | |||
| b4fb9af8e4 | |||
| ed6c9fe432 | |||
| 7e04aa438f | |||
| f1679f82c1 | |||
| 1808b81d59 | |||
| cd25c7acb2 | |||
| cf03779c5b | |||
| d3439f0d7e | |||
| 2df7f84939 | |||
| 74c76c48d5 | |||
| cdc0d22b01 | |||
| 5a520aadc0 | |||
| ec87489dd4 | |||
| e30affdfc2 | |||
| 66bd2559b9 | |||
| c8d6b1fab0 | |||
| 548c59719b | |||
| 59c1e24371 | |||
| 3c09921cbd | |||
| 00f3d450f9 | |||
| e676387c16 | |||
| 2e2e8a2230 | |||
| 8c8ede361e | |||
| 672bf05856 | |||
| 67ec31c75a | |||
| 59d13a7810 | |||
| 010a25f4cb | |||
| a0ac7b4a1e | |||
| ab7eb89466 | |||
| 649d362b85 | |||
| cb80860d6f | |||
| a8ef9e66fc | |||
| d27212e0b7 | |||
| 65650a7ae5 | |||
| 6ab5b8eb68 | |||
| c618e0577a | |||
| 0e84c91451 | |||
| 005ce11313 | |||
| db118d4f5a | |||
| c92b30a741 | |||
| d67aec6fec | |||
| ce58f25488 | |||
| e8d77a3c61 | |||
| d6d7fc1edd | |||
| 7ce7f8bfce | |||
| f0f46e5272 | |||
| f9473cc8bc | |||
| 5c7d31157b | |||
| 982a512ebd | |||
| 5dfd3d2f5d | |||
| 8d6974f67d | |||
| 8b569e3cd8 | |||
| b9d20142a2 | |||
| 6c9e818abd | |||
| d2a287d43c | |||
| d6ce2e364f | |||
| 36ca485a74 | |||
| b3230c5671 | |||
| ebf490838c | |||
| 7921cf18b6 | |||
| 0e0450ced5 | |||
| 096064ac09 | |||
| 77c2d7d846 | |||
| 40a121198d | |||
| 44079a7bf7 | |||
| 50fa013801 | |||
| d4ccf0ec62 | |||
| 04842974e7 | |||
| 6161b08f82 | |||
| b9818a4480 | |||
| e2ae22421b | |||
| b64677e14a | |||
| c910445634 | |||
| c4683a754e | |||
| 1da8fdb588 | |||
| 4bf8e342dc | |||
| 18fc50fcbf | |||
| 2fb10b7076 | |||
| 967291c2ef | |||
| 392ae871d5 | |||
| 27b3070480 | |||
| 325f59e03d | |||
| 217ffb36e6 | |||
| 4afad93ff6 | |||
| e8858cb1b7 | |||
| 52de31c9a6 | |||
| 60660a1f1a | |||
| a2ea9db90e | |||
| 236a7dadc6 | |||
| 82d2cc943d | |||
| d70f462899 | |||
| 0a636b5899 | |||
| e0b2749188 | |||
| 2fc973245d | |||
| 9bfcb64542 | |||
| 61e34b7ef8 | |||
| 3c3078875a | |||
| 5293e2c13d | |||
| fdf3b3f581 | |||
| f3f29fb54f | |||
| e8ed79a6bb | |||
| cca730d927 | |||
| 0693cb7840 | |||
| 3f1958cce1 | |||
| fb708bed90 | |||
| 1636587a82 | |||
| 1f1ccd81bb | |||
| 5efb0eb582 | |||
| be5f71c123 | |||
| a0df6bfc12 | |||
| 2ab0dc20d7 | |||
| 175ce3613a | |||
| eecb5c3754 | |||
| b34360901f | |||
| 21bbd21ae9 | |||
| 0b403a4c5d | |||
| 1d1e1beca5 | |||
| 3d4d844e72 | |||
| 1f9aa72bdb | |||
| c29f68e35d | |||
| c7c10e769d | |||
| 7264c01b85 | |||
| 97faa7413f | |||
| 7531c48e38 | |||
| 16799d8b75 | |||
| 901115ed10 | |||
| 596ca08446 | |||
| 4d864d8cad | |||
| c458a35670 | |||
| c203bfe5ad | |||
| 8b2a838388 | |||
| b08212e2f9 | |||
| b5f08838b3 | |||
| 5501605a1f | |||
| 7a5197df63 | |||
| 09d45aa64b | |||
| 552810359e | |||
| a68a6885d0 | |||
| b32589f7e7 | |||
| 2e6b8a067d | |||
| 581fdfdfe0 | |||
| 8e4ff39738 | |||
| f568803af2 | |||
| 6db06857ba | |||
| fd4dd13270 | |||
| ded9f332f6 | |||
| d09ca46141 | |||
| b28cd7f8bd | |||
| a4054aa500 | |||
| 3332bfcee1 | |||
| cc798a0c0a | |||
| fe2030b7e3 | |||
| ed1cce86ef | |||
| 9a544b0ff3 | |||
| 82f7b29836 | |||
| 076acfb242 | |||
| ed336bc0ff | |||
| 5699446d69 | |||
| a43d32949e | |||
| 02a1e648bc | |||
| 9d3e0651e2 | |||
| cdff5a9039 | |||
| ba0b5500ca | |||
| 1439a7e289 | |||
| 9761ede5c4 | |||
| e342805752 | |||
| d08672aa71 | |||
| a3d4e05b0e | |||
| 51eeed3d50 | |||
| 51c45456c3 | |||
| 074ba63bf5 | |||
| f3d552d8a0 | |||
| c5fb4a9228 | |||
| 55d7e910e4 | |||
| ea29af8d3d | |||
| 88b9d71bd7 | |||
| 165c84c246 | |||
| 347820867d | |||
| 26d0dfbf3d | |||
| 6aa4849266 | |||
| 335b3802b8 | |||
| 73bd3fa60c | |||
| 6b61c5900c | |||
| 9da4083096 | |||
| 86fe244d95 | |||
| 732f2846de | |||
| 4f238caf5c | |||
| c9388e9f56 | |||
| 2a9fa9539f | |||
| b8d136588c | |||
| 92c9e82dee | |||
| 0fdb48bda3 | |||
| e8d4fd7aac | |||
| 6a4a78a26a | |||
| 6c6769ca98 | |||
| 3e49af9093 | |||
| 5f8ecfa3fa | |||
| aca03d2609 | |||
| 5db9493d2b | |||
| ac3c041d6d | |||
| a319c0c94a | |||
| f74d619748 | |||
| eef1981f20 | |||
| ade9d86696 | |||
| 935c1cfeab | |||
| 5706770a11 | |||
| 2643417c0b | |||
| d388036601 | |||
| 96df75cc05 | |||
| c62d8d6753 | |||
| 1562c96d4c | |||
| 94c87d436f | |||
| b9c8ffb5cf | |||
| a37a23bcfc | |||
| 863ad22b48 | |||
| bce865ff9f | |||
| 1963fe208e | |||
| 5c4526725b | |||
| 3f42e9c5bd | |||
| b1c9d0a0af | |||
| adcbfb4b9e | |||
| b3ebccab36 | |||
| d5797054fb | |||
| aab0ec22b9 | |||
| f7babcc1d2 | |||
| d077307721 | |||
| 72e8e10bd6 | |||
| 5ea9e8a0d7 | |||
| 87b050fad2 | |||
| 0c8cd74e28 | |||
| 445d970784 | |||
| 125a1eb9fc | |||
| a2a578d04d | |||
| 11e5c0aa9d | |||
| 14b856b0cf | |||
| 2e8dd73822 | |||
| da9fdb356c | |||
| 054a99ca38 | |||
| baf33609af | |||
| b4eb0b6b41 | |||
| 3e9a47a683 | |||
| d71c3ecd86 | |||
| e5a864a760 | |||
| 81b59f9bc9 | |||
| 2c2a36ce34 | |||
| cb0020c629 | |||
| 003d39c8cd | |||
| ca866183f1 | |||
| b6e627369b | |||
| da96cfc158 | |||
| 0abbd53e07 | |||
| 6fc0f858c7 | |||
| b3613b68cd | |||
| 2b6619b3c4 | |||
| a33161aa9c | |||
| 5c3c5b999f | |||
| 7acca18313 | |||
| 7b71d9a448 | |||
| 64ffa3e70f | |||
| fd88972380 | |||
| dd7b09552a | |||
| 0b23aa9e7e | |||
| 0caa31bd6b | |||
| cafac135a0 | |||
| 6ac312bd49 | |||
| 489877d6bf | |||
| b0b2e695e1 | |||
| c3808c0c5b | |||
| c09545de64 | |||
| 7566b0159c | |||
| ed7cc9b89e | |||
| 55501e68fb | |||
| eabe670ae8 | |||
| 9fffef6f53 | |||
| 368429b757 | |||
| 49f774eb0d | |||
| 0487d7a058 | |||
| 5943e77563 | |||
| b10f0fb945 | |||
| c299891fb0 | |||
| fe0f22dfc0 | |||
| 002603c388 | |||
| 30ef8456c3 | |||
| bee1ce401a | |||
| e18c4a370a | |||
| 2a60a929f1 | |||
| 939295ab04 | |||
| f6a0ef6a61 | |||
| b3bce314e9 | |||
| e28b85d8b6 | |||
| a0af2fc997 | |||
| 7f7f5c6f12 | |||
| d21fbfc9be | |||
| 366dc1cca9 | |||
| e9e3913bb7 | |||
| 5491f6eff7 | |||
| 32e36ba324 | |||
| 9d4c456461 | |||
| cdc7920dff | |||
| cdb4901d91 | |||
| c7f3520ea8 | |||
| f0e728c316 | |||
| 4b1f127eaf | |||
| 1db2d8d8d8 | |||
| 87bb45d01b | |||
| 6beadcece8 | |||
| fc6f0f3a86 | |||
| ef7370f56d | |||
| 52ba7cdbff | |||
| b0c9dd44e9 | |||
| 92ec093ed9 | |||
| 6d2a1aafd2 | |||
| f3a7734584 | |||
| 9cf92f37f5 | |||
| 34831d42a4 | |||
| 607d5d7841 | |||
| 75adfd2e9d | |||
| e92b5b2d35 | |||
| a8c40a5493 | |||
| be5c3fb55c | |||
| e6e4a63022 | |||
| 1cdc8928ba | |||
| ad111a0163 | |||
| 7091a4899c | |||
| 3bd9e70fa9 | |||
| 54bd2c620e | |||
| 121640b1b3 | |||
| 55e388513c | |||
| b153dcbd63 | |||
| 242cbe5ecb | |||
| f1cca13796 | |||
| 918ba72107 | |||
| e596f27666 | |||
| a40d0000c5 | |||
| fb82da74a1 | |||
| b0991a0624 | |||
| 6236acea02 | |||
| 391c7e8570 | |||
| 58041cc64e | |||
| 8c7d3a6e92 | |||
| ae1982369c | |||
| 5f85ac01f7 | |||
| cca263fb2b | |||
| 809ed02b85 | |||
| 9eab1083ab | |||
| 60523bef80 | |||
| 46b959ff3c | |||
| 42c3827ded | |||
| 26e4b4efda | |||
| 2169ab3bb8 | |||
| 85dad8db88 | |||
| 8120c34064 | |||
| 1f1d1f70a1 | |||
| 373d868a17 | |||
| 834ba9bc61 | |||
| 3ffec5aed9 | |||
| ef20c1d684 | |||
| 697a59568c | |||
| e58fb935b0 | |||
| 044d23f8a5 | |||
| 1604d867c3 | |||
| 011db481c3 | |||
| c404cdc38a | |||
| 20689af7dd | |||
| 9ea0585d71 | |||
| 614c5f694b | |||
| fa36aae068 | |||
| 3e85232310 | |||
| 894928d7ca | |||
| afb1486f86 | |||
| 2799bd18e1 | |||
| 43c2a885b9 | |||
| be7feb0eaa | |||
| e3d653a8d9 | |||
| b9f9d8160d | |||
| 141b5c604d | |||
| 8a0fc00435 | |||
| a3a8cb9368 | |||
| 96c66b33a2 | |||
| 62fad3724f | |||
| ca2b6c87ef | |||
| 20348645a3 | |||
| a9b39fad64 | |||
| 1c556ade57 | |||
| e08957f5ec | |||
| e76ded69e6 | |||
| 7e740861d8 | |||
| f28e65a26c | |||
| a29f0c820b | |||
| b2bc30cfed | |||
| 6ce235bb68 | |||
| 479ab989df | |||
| 8d490b9e52 | |||
| 949f11a8c9 | |||
| d4896e1978 | |||
| c4020080b3 | |||
| 5a68003d16 | |||
| 9fcc3cdc24 | |||
| ee80ce5ae6 | |||
| 456c4019c4 | |||
| f65627a505 | |||
| 38d1fc15fe | |||
| 5eead5b0fa | |||
| 4223bd57f1 | |||
| 5bfa653858 | |||
| 5342764caf | |||
| 04a44a82c9 | |||
| c28820f39c | |||
| 546955a78b | |||
| d1e9cc5800 | |||
| 4ef2fb9933 | |||
| d7bc8adf21 | |||
| b5f44efc69 | |||
| 5e8abea222 | |||
| f291454ccb | |||
| bac6637b46 | |||
| 866ac9fb72 | |||
| 8208f6947f | |||
| dcd50a7c62 | |||
| 781aa86568 | |||
| 3facc116c8 | |||
| 9178c3b087 | |||
| 5c6c85a22f | |||
| b8adb4d229 | |||
| 093118da8b | |||
| 0aa760119f | |||
| 60b3a1583d | |||
| 593c47b938 | |||
| 0f6bb7ce6f | |||
| 048c2541e6 | |||
| f3e7d1a43b | |||
| 5df24d6683 | |||
| 73779898b7 | |||
| 7200b6adc6 | |||
| d48f15ab4d | |||
| 2747671935 | |||
| d86f24dd35 | |||
| 60edccade5 | |||
| 540460cae9 | |||
| df44d86f46 | |||
| c287b446c9 | |||
| 1db36c05a8 | |||
| 2c884ab5ab | |||
| cd0dfc956d | |||
| 03392a5f03 | |||
| a7da999bd7 | |||
| 47f21b1652 | |||
| 7c91d10c79 | |||
| fac2f5494b | |||
| bfcdb7e840 | |||
| 21d55db3b4 | |||
| 18e49888fe | |||
| 7ba2f61361 | |||
| 407df158ef | |||
| eab46ba9c4 | |||
| 39318e5e61 | |||
| ac1ce03fe5 | |||
| 4fa697ec75 | |||
| 027961bffa | |||
| 7dfcbabe0c | |||
| dfc7658426 | |||
| 04c6726b76 | |||
| 8fdbbe4c16 | |||
| 09fceab75b | |||
| 8df4c27285 | |||
| e38820b74a | |||
| c052e731f8 | |||
| 3636860262 | |||
| ce7421bef4 | |||
| 23b51c4c3e | |||
| 48d802fc40 | |||
| 51e8f3ff6e | |||
| 7917397bf3 | |||
| e0c0052b63 | |||
| 15a4b50ce4 | |||
| a51a8abf27 | |||
| 45747e3635 | |||
| 64b8e15918 | |||
| f4b716b255 | |||
| 1115ff83bb | |||
| c24550c756 | |||
| b5cdfe30ea | |||
| a10e594da1 | |||
| 63aee387f0 | |||
| ab9de1e199 | |||
| e60c463328 | |||
| 537d74196b | |||
| a8bbbe8582 | |||
| 29471a7aac | |||
| 894a4a5567 | |||
| f7cd5276f0 | |||
| 95b8c71083 | |||
| 52c82e6fe2 | |||
| cef1abd6aa | |||
| 91da261128 | |||
| 1c70346a61 | |||
| 2de017086d | |||
| d6253c72d4 | |||
| e5007b6c87 | |||
| bbc18549b3 | |||
| b6855b6fba | |||
| 70db97d576 | |||
| f632f2f39e | |||
| b23f968d57 | |||
| ea88877a11 | |||
| 1de3decede | |||
| 78045fd2ab | |||
| 7c8898158b | |||
| 3fc5f87388 | |||
| 623ca1effc | |||
| da05e7fe5e | |||
| f3734d4c64 | |||
| 9ab458e109 | |||
| d4c72e6f78 | |||
| 1f58ef5140 | |||
| 69d574c587 | |||
| a027fdded7 | |||
| 443df0501d | |||
| d68fe5f80d | |||
| ebf868bae3 | |||
| 8a9b3286e9 | |||
| a0455561b6 | |||
| 518ccf5a74 | |||
| 54f09c58cb | |||
| 029ad1045a | |||
| 2f55fb4d84 | |||
| add724eee9 | |||
| 07324ae892 | |||
| ffc05e971f | |||
| 30f42fd1d4 | |||
| f284857438 | |||
| 06ab514472 | |||
| 85b65acbe0 | |||
| 4d1d9de22f | |||
| a68ec9b191 | |||
| e386636d66 | |||
| cc3311b8eb | |||
| d3d1181769 | |||
| 001abf684c | |||
| 92a65296b5 | |||
| 3a7887d003 | |||
| 3334c4a87a | |||
| 228ce768e0 | |||
| eafc1a784c | |||
| fd3a4d0a0e | |||
| 77d679b63b | |||
| 730d764c6e | |||
| 6f1ef82e89 | |||
| d4da910f19 | |||
| a0a0773bd2 | |||
| 9ce8d138d5 | |||
| 0041b034e0 | |||
| d781c437de | |||
| 2fe21b8547 | |||
| dbc90c9417 | |||
| 431d60a58a | |||
| fcfcc9a94a | |||
| 870fb4e2df | |||
| e3612b973f | |||
| 75f4ca928f | |||
| 22fd25b30f | |||
| 610ddb09ff | |||
| 33602aca11 | |||
| a207856e99 | |||
| 80e8b5b5e4 | |||
| 273996aa91 | |||
| 646b88c5be | |||
| 88cfd82a25 | |||
| 2f8436be87 | |||
| a6237cdda3 | |||
| eb93a767fc | |||
| 41852412ca | |||
| 224b2b7323 | |||
| ec939f9f9a | |||
| eced15b712 | |||
| f8fb473981 | |||
| f2bcb77cfb | |||
| dc5da28176 | |||
| be43e64743 | |||
| 454630dace | |||
| c9df244333 | |||
| 2649d97d69 | |||
| bcb9ac5501 | |||
| 76d1e26f7d | |||
| ba13ab9926 | |||
| c43b34b67f | |||
| 3739c2881b | |||
| bc13b81351 | |||
| 86a56e487a | |||
| 031058cd0c | |||
| 85040d6104 | |||
| efbf74b44c | |||
| 774fc42e8e | |||
| 692cfe4f52 | |||
| 8b34d4417b | |||
| c20a7b3c69 | |||
| ff6e83c55e | |||
| 6aa56fd30f | |||
| f5a6f129dd | |||
| 5405c1d240 | |||
| 455f85e230 | |||
| fa899a67a7 | |||
| 56cf25eebf | |||
| 1a490551e6 | |||
| 4514802e35 | |||
| a9062b0611 | |||
| eb6b30aab1 | |||
| 922abd7ad3 | |||
| c4596dda75 | |||
| 168b77326b | |||
| f674bba861 | |||
| 6b2e65e738 | |||
| 51021c799d | |||
| 01cb036976 | |||
| ea7867429f | |||
| c5300cd7be | |||
| ea34c7d226 | |||
| 537e04989f | |||
| d447c5dc25 | |||
| 73944fc9bf | |||
| 01e994e0f1 | |||
| af3f3f436c | |||
| 56e90a266a | |||
| 1fc59ed522 | |||
| 3a3b1a6c17 | |||
| 242ce807df | |||
| 734967152c | |||
| 8023e15bb9 | |||
| ceb58a6fe1 | |||
| ae48bd1abb | |||
| d27fe2fbad | |||
| 970686efaf | |||
| 8df46ec0e9 | |||
| 864057a6ed | |||
| 92ca4cb1d1 | |||
| aabf811fe7 | |||
| 9b0a645a05 | |||
| 24b5e7ff09 | |||
| 48969ecee3 | |||
| 6ae0912e0e | |||
| e8062d544d | |||
| 07332aa4ac | |||
| 1e2b3559f2 | |||
| 8bfaa14edb | |||
| d4e87d3fe8 | |||
| 460348c0b6 | |||
| 264e8c735e | |||
| c4b04e2327 | |||
| dc1389bd1a | |||
| 51e38c80d8 | |||
| a33f5fabd1 | |||
| e6c8344970 | |||
| 2207ae6617 | |||
| cdc6707ad3 | |||
| 448fdaecbd | |||
| 4aa79aed6f | |||
| c8fcc373f8 | |||
| 1410141b46 | |||
| 76efabb5f3 | |||
| 36effc6dc4 | |||
| 8d5412a38f | |||
| 465b5d20b4 | |||
| 60a22b1897 | |||
| 09a685e977 | |||
| 31da90865c |
@@ -0,0 +1,6 @@
|
||||
# Set default behaviour to automatically normalize line endings.
|
||||
* text=auto
|
||||
|
||||
# Force bash scripts to always use lf line endings so that if a repo is accessed
|
||||
# in Unix via a file share from Windows, the scripts will work.
|
||||
*.sh text eol=lf
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Please search existing issues to avoid duplicates. -->
|
||||
|
||||
## Details
|
||||
|
||||
|
||||
### Backends
|
||||
|
||||
This bug occurs on ( insert `x` below )
|
||||
|
||||
Backend | yes | no | untested
|
||||
-------------|-----|-----|---------
|
||||
gr (default) | | |
|
||||
pyplot | | |
|
||||
plotly | | |
|
||||
plotlyjs | | |
|
||||
pgfplotsx | | |
|
||||
inspectdr | | |
|
||||
|
||||
### Versions
|
||||
|
||||
Plots.jl version:
|
||||
Backend version (`]st -m`):
|
||||
Output of `versioninfo()`:
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a feature or enhancement
|
||||
title: "[FR]"
|
||||
labels: feature request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please search existing issues to avoid duplicates.
|
||||
@@ -0,0 +1,17 @@
|
||||
name: CompatHelper
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 00 * * *'
|
||||
|
||||
jobs:
|
||||
CompatHelper:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Pkg.add("CompatHelper")
|
||||
run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
|
||||
- name: CompatHelper.main()
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} # optional
|
||||
run: julia -e 'using CompatHelper; CompatHelper.main()'
|
||||
@@ -0,0 +1,89 @@
|
||||
name: SnoopCompile
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
# - 'master' # NOTE: to run the bot only on pushes to master
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
SnoopCompile:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
env:
|
||||
GKS_ENCODING: "utf8"
|
||||
GKSwstype: "100"
|
||||
PLOTS_TEST: "true"
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: # NOTE: the versions below should match those in your botconfig
|
||||
- '1.5'
|
||||
os: # NOTE: should match the os setting of your botconfig
|
||||
- ubuntu-latest
|
||||
arch:
|
||||
- x64
|
||||
steps:
|
||||
# Setup environment
|
||||
- uses: actions/checkout@v2
|
||||
- uses: julia-actions/setup-julia@latest
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
julia --project -e 'using Pkg; Pkg.instantiate();'
|
||||
julia -e 'using Pkg; Pkg.add( PackageSpec(name = "CompileBot", version = "1") ); Pkg.develop(PackageSpec(; path=pwd())); using CompileBot; CompileBot.addtestdep();'
|
||||
|
||||
|
||||
# TESTCMD
|
||||
- name: Default TESTCMD
|
||||
run: echo "TESTCMD=julia" >> $GITHUB_ENV
|
||||
- name: Ubuntu TESTCMD
|
||||
if: startsWith(matrix.os,'ubuntu')
|
||||
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
|
||||
|
||||
# Generate precompile files
|
||||
- name: Generating precompile files
|
||||
run: $TESTCMD --project -e 'include("deps/SnoopCompile/snoop_bot.jl")' # NOTE: must match path
|
||||
|
||||
# Run benchmarks
|
||||
- name: Running Benchmark
|
||||
run: $TESTCMD --project -e 'include("deps/SnoopCompile/snoop_bench.jl")' # NOTE: optional, if have benchmark file
|
||||
|
||||
- name: Upload all
|
||||
uses: actions/upload-artifact@v2.0.1
|
||||
with:
|
||||
path: ./
|
||||
|
||||
Create_PR:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
needs: SnoopCompile
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download all
|
||||
uses: actions/download-artifact@v2
|
||||
|
||||
- name: CompileBot postprocess
|
||||
run: julia -e 'using Pkg; Pkg.add( PackageSpec(name = "CompileBot", version = "1") ); using CompileBot; CompileBot.postprocess();'
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update precompile_*.jl file
|
||||
title: "[AUTO] Update precompiles"
|
||||
labels: SnoopCompile
|
||||
branch: "Test_SnoopCompile_AutoPR_${{ github.ref }}"
|
||||
|
||||
|
||||
Skip:
|
||||
if: "contains(github.event.head_commit.message, '[skip ci]')"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Skip CI 🚫
|
||||
run: echo skip ci
|
||||
@@ -0,0 +1,14 @@
|
||||
name: TagBot
|
||||
on:
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
TagBot:
|
||||
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: JuliaRegistries/TagBot@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Run benchmarks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
Benchmark:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
env:
|
||||
GKS_ENCODING: "utf8"
|
||||
GKSwstype: "100"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: julia-actions/setup-julia@latest
|
||||
with:
|
||||
version: 1
|
||||
|
||||
## Setup
|
||||
- name: Ubuntu TESTCMD
|
||||
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
|
||||
- name: Install Plots dependencies
|
||||
uses: julia-actions/julia-buildpkg@latest
|
||||
- name: Install Benchmarking dependencies
|
||||
run: julia -e 'using Pkg; pkg"add PkgBenchmark BenchmarkCI@0.1"'
|
||||
|
||||
- name: Run benchmarks
|
||||
run: $TESTCMD -e 'using BenchmarkCI; BenchmarkCI.judge()'
|
||||
- name: Print judgement
|
||||
run: julia -e 'using BenchmarkCI; BenchmarkCI.displayjudgement()'
|
||||
- name: Post results
|
||||
run: julia -e 'using BenchmarkCI; BenchmarkCI.postjudge()'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,86 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
CI:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
env:
|
||||
GKS_ENCODING: "utf8"
|
||||
GKSwstype: "100"
|
||||
|
||||
name: Julia ${{ matrix.version }} - ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.version == 'nightly' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version:
|
||||
- '1'
|
||||
- 'nightly'
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
- macos-latest
|
||||
arch:
|
||||
- x64
|
||||
# - x86
|
||||
|
||||
steps:
|
||||
|
||||
# Setup environment
|
||||
- uses: actions/checkout@v2
|
||||
- uses: julia-actions/setup-julia@latest
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
- name: Cache artifacts
|
||||
uses: actions/cache@v1
|
||||
env:
|
||||
cache-name: cache-artifacts
|
||||
with:
|
||||
path: ~/.julia/artifacts
|
||||
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-test-${{ env.cache-name }}-
|
||||
${{ runner.os }}-test-
|
||||
${{ runner.os }}-
|
||||
|
||||
## maybe required if we ever want to run graphical tests for plotly
|
||||
# OS Dependencies
|
||||
# - name: Ubuntu OS dependencies
|
||||
# if: startsWith(matrix.os,'ubuntu')
|
||||
# run: |
|
||||
# ./test/install_wkhtmltoimage.sh
|
||||
|
||||
# TESTCMD
|
||||
- name: Default TESTCMD
|
||||
run: echo "TESTCMD=julia" >> $GITHUB_ENV
|
||||
- name: Ubuntu TESTCMD
|
||||
if: startsWith(matrix.os,'ubuntu')
|
||||
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
|
||||
|
||||
# Julia Dependencies
|
||||
- name: Install Julia dependencies
|
||||
uses: julia-actions/julia-buildpkg@latest
|
||||
|
||||
# Run tests
|
||||
- name: Run Graphical test
|
||||
run: $TESTCMD --project -e 'using Pkg; Pkg.test(coverage=true);'
|
||||
|
||||
- name: Codecov
|
||||
uses: julia-actions/julia-uploadcodecov@latest
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
Skip:
|
||||
if: "contains(github.event.head_commit.message, '[skip ci]')"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Skip CI 🚫
|
||||
run: echo skip ci
|
||||
@@ -1,3 +1,14 @@
|
||||
*.jl.cov
|
||||
*.jl.*.cov
|
||||
*.jl.mem
|
||||
.DS_Store
|
||||
examples/.ipynb_checkpoints/*
|
||||
examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-*
|
||||
deps/build.log
|
||||
deps/deps.jl
|
||||
Manifest.toml
|
||||
dev/
|
||||
test/tmpplotsave.hdf5
|
||||
/.benchmarkci
|
||||
/benchmark/*.json
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Documentation: http://docs.travis-ci.com/user/languages/julia/
|
||||
language: julia
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
julia:
|
||||
- 0.4
|
||||
notifications:
|
||||
email: false
|
||||
# uncomment the following lines to override the default test script
|
||||
script:
|
||||
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots"); Pkg.add("Gadfly"); Pkg.test("Plots"; coverage=true)'
|
||||
@@ -0,0 +1,824 @@
|
||||
|
||||
# Plots.jl NEWS
|
||||
|
||||
#### notes on release changes, ongoing development, and future planned work
|
||||
|
||||
## (current master)
|
||||
|
||||
## 0.28.3
|
||||
- support generalized array interface
|
||||
- save to pdf, svg and eps in plotlyjs
|
||||
- fix for clims in line_z
|
||||
- optimize heatmap logic in gr
|
||||
|
||||
## 0.26.3
|
||||
- fix `vline` with dates
|
||||
- fix PyPlot logscale bug
|
||||
- avoid annotation clipping for PyPlot
|
||||
- allow plotting of Any vectors and 3D plotting again in convertToAnyVector
|
||||
- specify legend title font in GR and PyPlot
|
||||
- delete `pushtomaster.sh`
|
||||
- use `=== nothing`
|
||||
|
||||
## 0.26.2
|
||||
- improve empty animation build error
|
||||
- fix GR axis flip for heatmaps and images
|
||||
- fix ribbons specified as tuples
|
||||
- add Char recipe
|
||||
- fix Plotly plots with single-element series
|
||||
- rewrite PlotlyJS backend
|
||||
|
||||
## 0.26.1
|
||||
- handle `Char`s as input data
|
||||
- fix html saving for Plotly
|
||||
- expand ~ in paths on UNIX systems
|
||||
- convertToAnyVector clean-up
|
||||
- fix color_palette grouping issue
|
||||
|
||||
## 0.26.0
|
||||
- use FFMPEG.jl
|
||||
- add missing method for convertToAnyVector
|
||||
|
||||
## 0.25.3
|
||||
- add areaplot
|
||||
- allow missing in z_color arguments
|
||||
- more general tuple recipe
|
||||
- stephist logscale improvements
|
||||
|
||||
## 0.25.2
|
||||
- improvements to handle missings
|
||||
- pyplot: allow setting the color gradient for z values
|
||||
- document :colorbar_entry
|
||||
- limit number of automatic bins
|
||||
- fix ENV['PLOTS_DEFAULT_BACKEND']
|
||||
- don't let aspect_ratio impact subplot size
|
||||
- implement arrowstyle for GR
|
||||
- fix bug in plotly_convert_to_datetime
|
||||
- improve missing support
|
||||
- gr: polar heatmaps
|
||||
- make sure show returns nothing
|
||||
|
||||
## 0.25.1
|
||||
- fix gr_display
|
||||
|
||||
## 0.25.0
|
||||
- Replace StaticArrays with GeometryTypes
|
||||
- Contour fixes for GR
|
||||
|
||||
## 0.24.0
|
||||
- Update to the new PyCall and PyPlot API
|
||||
- fix drawing of ticks
|
||||
- fix y label position with GR
|
||||
|
||||
## 0.23.2
|
||||
- pyplot fixes
|
||||
- Add option :tex_output_standalone to set the 'include_preamble' argument in the PGFPlots backend.
|
||||
- fix ticks
|
||||
- support plotly json mime
|
||||
- fix image axis limits
|
||||
- default to radius 0 at center for polar plots
|
||||
|
||||
## 0.23.1
|
||||
- slightly faster load time
|
||||
- fixed errant MethodError
|
||||
- fix bar plots with unicodeplots
|
||||
- better colorbars for contour
|
||||
- add volume seriestype for GR
|
||||
- fix passing a tuple to custom ticks
|
||||
- add vline to pgfplots
|
||||
- add tex output for pyplot
|
||||
- better 3d axis labels for GR
|
||||
|
||||
## 0.23.0
|
||||
- compatible with StatPlots -> StatsPlots name shift
|
||||
- fix histograms for vectors with NaN and Inf
|
||||
- change gif behaviour (remove cache-busting)
|
||||
- improved docstrings for shorthands functions
|
||||
- fix font rotation for pyplot
|
||||
- fix greyscale images for pyplot
|
||||
- clamp greyscale images with values outside 0,1
|
||||
- support keyword argument for font options
|
||||
- allow vector of markers for pyplot scatter
|
||||
|
||||
## 0.22.5
|
||||
- improve behaviour of plotlyjs backend
|
||||
|
||||
## 0.22.4
|
||||
- Add support for discrete contourf plots with GR
|
||||
|
||||
## 0.22.3
|
||||
- Fix the `showtheme` function
|
||||
|
||||
## 0.22.2
|
||||
- Allow annotations to accept a Tuple instead of the result of a text call (making it possible to specify font characteristics in recipes). E.g. `annotations = (2, 4, ("test", :right, 8, :red))` is the same as `annotations = (2, 4, text("test", :right, 8, :red))`
|
||||
|
||||
## 0.22.1
|
||||
- push PlotsDisplay just after REPLDisplay
|
||||
|
||||
## 0.22.0
|
||||
- deprecate GLVisualize
|
||||
- allow 1-row and 1-column heatmaps
|
||||
- add portfoliodecomposition recipe from PlotRecipes
|
||||
- solve Shape bug
|
||||
- simplify PyPlot backend installation
|
||||
- fix wireframe bug in PyPlot
|
||||
- fix color bug in PyPlot
|
||||
- minor bug fixes in gr and pyplot
|
||||
|
||||
## 0.21.0
|
||||
- Compatibility with StaticArrays 0.9.0
|
||||
- Up GR min version to 0.35
|
||||
- fix :mirror
|
||||
|
||||
## 0.20.6
|
||||
- fixes for PlotDocs.jl
|
||||
- fix gr axis color argument
|
||||
- Shapes for inspectdr
|
||||
- don't load plotly js file by default
|
||||
|
||||
## 0.20.5
|
||||
- fix precompilation issue when depending on Plots
|
||||
|
||||
## 0.20.4
|
||||
- honour `html_output_format` in Juno
|
||||
|
||||
## 0.20.3
|
||||
- implement guide position in gr, pyplot and pgfplots
|
||||
- inspectdr fixes
|
||||
- default appveyor
|
||||
- rudimentary missings support
|
||||
- deprecation fixes for PGFPlots
|
||||
|
||||
## 0.20.0
|
||||
Many updates, min julia 1.0
|
||||
- change display type to use PlotsDisplay (fixes Juno integration)
|
||||
- change all internal uses of `d` to `plotattributes` (no user change)
|
||||
- change spy implementation to use `scatter` not `heatmap`
|
||||
- sort x axes when passing a vector of strings as x
|
||||
- improve performance of marker_z
|
||||
- update CI to 1.0
|
||||
- minor depwarn ifixes
|
||||
- only draw one colorbar with GR
|
||||
- add colorbar_title to GR and pgfplots
|
||||
- fix savefig with latexstrings for PyPlot
|
||||
- fix NamedTuple integration
|
||||
- don't export `P2` and `P3`
|
||||
- make it possible to use 2-argument function as argument to marker_z
|
||||
- make `plotattr` work again
|
||||
|
||||
## 0.19.3
|
||||
- fix some julia 0.7 deprecations
|
||||
- fix 32-bit OS functionality
|
||||
|
||||
## 0.19.2
|
||||
- several small fixes for 1.0 compatibility
|
||||
|
||||
## 0.19.1
|
||||
- don't broadcast plot_color
|
||||
|
||||
## 0.19.0
|
||||
- Refactor conditional loading to use Requires
|
||||
- Many fixes for 1.0 compatibility
|
||||
|
||||
## 0.18.0
|
||||
- update minor version to 0.7
|
||||
|
||||
## 0.17.4
|
||||
- fix thickness_scaling for pyplot
|
||||
|
||||
## 0.17.3
|
||||
- Log-scale heatmap edge computation
|
||||
- Fix size and dpi for GR and PyPlot
|
||||
- Fix fillrange with line segments on PyPlot and Plotly
|
||||
- fix flip for heatmap and image on GR
|
||||
- New attributes for PGFPlots
|
||||
- Widen axes for most series types and log scales
|
||||
- Plotly: fix log scale with no ticks
|
||||
- Fix axis flip on Plotly
|
||||
- Fix hover and zcolor interaction in Plotly
|
||||
- WebIO integration for PlotlyJS backend
|
||||
|
||||
## 0.17.2
|
||||
- fix single subplot in plotly
|
||||
- implement `(xyz)lims = :round`
|
||||
- PyPlot: fix bg_legend = invisible()
|
||||
- set fallback tick specification for axes with discrete values
|
||||
- restructure of show methods
|
||||
|
||||
## 0.17.1
|
||||
- Fix contour for PGFPlots
|
||||
- 32Bit fix: Int64 -> Int
|
||||
- Make series of shapes and segments toggle together in Plotly(JS)
|
||||
- Fix marker arguments
|
||||
- Fix processing order of series recipes
|
||||
- Fix Plotly(JS) ribbon
|
||||
- Contour plots with x,y in grid form on PyPlot
|
||||
|
||||
## 0.17.0
|
||||
- Add GR dependency to make it the default backend
|
||||
- Improve histogram2d bin estimation
|
||||
- Allow vector arguments for certain series attributes and support line_z and fill_z on GR, PyPlot, Plotly(JS) and PGFPlots
|
||||
- Automatic scientific notation for tick labels
|
||||
- Allow to set the theme in PLOTS_DEFAULTS
|
||||
- Implement plots_heatmap seriestype providing a Plots recipe for heatmaps
|
||||
|
||||
## 0.16.0
|
||||
- fix 3D plotting in PyPlot
|
||||
- Infinite objects
|
||||
|
||||
## 0.15.1
|
||||
|
||||
- fix scientific notation for labels in GR
|
||||
- fix labels with logscale
|
||||
- fix image cropping with GR
|
||||
- fix grouping of annotations
|
||||
- fix annotations in Plotly
|
||||
- allow saving notebook with plots as pdf from IJulia
|
||||
- fix fillrange and ribbon for step recipes
|
||||
- implement native ticks that respond to zoom
|
||||
- fix bar plot with one bar
|
||||
- contour labels and colorbar fixes
|
||||
- interactive linked axis for PyPlot
|
||||
- add `NamedTuple` syntax to group with named legend
|
||||
- use bar recipe in Plotly
|
||||
- implement categorical ticks
|
||||
|
||||
## 0.15.0
|
||||
|
||||
- improve resolution of png output of GR with savefig()
|
||||
- add check for ticks=nothing
|
||||
- allow transparency in heatmaps
|
||||
- fix line_z for GR
|
||||
- fix legendcolor for pyplot
|
||||
- fix pyplot ignoring alpha values of images
|
||||
- don't let `abline!` change subplot limits
|
||||
- update showtheme recipe
|
||||
|
||||
## 0.14.2
|
||||
|
||||
- fix plotly bar lines bug
|
||||
- allow passing multiple series to `ribbon`
|
||||
- add a new example for `line_z`
|
||||
|
||||
## 0.14.1
|
||||
|
||||
- Add linestyle argument to the legend
|
||||
- Plotly: bar_width and stroke_width support for bar plots
|
||||
- abline! does not change axis limits
|
||||
- Fix default log scale ticks in GR backend
|
||||
- Use the :fontsize keys so the scalefontsizes command works
|
||||
- Prepare support for new PlotTheme type in PlotThemes
|
||||
|
||||
## 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 StatsPlots 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
|
||||
- `grid` is now an axis attribute and a magic argument: it is now possible to modify the grid line style, alpha and line width
|
||||
- Enforce plot order in user recipes
|
||||
- import `plot!` from RecipesBase
|
||||
- GR no longer automatically handles _ and ^ in texts
|
||||
- fix GR colorbar for scatter plots
|
||||
|
||||
#### 0.12.2
|
||||
|
||||
- fix an issue with Juno/PlotlyJS compatibility on new installations
|
||||
- fix markers not showing up in seriesrecipes using :scatter
|
||||
- don't use pywrap in the pyplot backend
|
||||
- improve the bottom margin for the gr backend
|
||||
|
||||
#### 0.12.1
|
||||
|
||||
- fix deprecation warnings
|
||||
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
|
||||
- drop FactCheck in tests
|
||||
- remove julia 0.5 compliant uses of transpose operator
|
||||
- fix GR heatmap bugs
|
||||
- fix GR guide padding
|
||||
- improve legend markers in GR
|
||||
- add surface alpha for Plotly(JS)
|
||||
- add fillrange to Plotly(JS)
|
||||
- allow usage of Matplotlib 1.5 with PyPlot
|
||||
- fix GLVisualize for julia 0.6
|
||||
- conform to changes in InspectDR
|
||||
|
||||
#### 0.12.0
|
||||
|
||||
- 0.6 only
|
||||
|
||||
#### 0.11.3
|
||||
|
||||
- add HDF5 backend
|
||||
- GR replaces PyPlot as first-choice backend
|
||||
- support for legend position in GR
|
||||
- smaller markers in GR
|
||||
- better viewport size in GR
|
||||
- fix glvisualize support
|
||||
- remove bug with three-argument method of `text`
|
||||
- `legendtitle` attribute added
|
||||
- add test for `spy`
|
||||
|
||||
#### 0.11.0
|
||||
|
||||
- julia 0.6 compatibility
|
||||
- matplotlib 2.0 compatibility
|
||||
- add inspectdr backend
|
||||
- improved histogram functionality:
|
||||
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)
|
||||
- support for log scale axes with histograms
|
||||
- support for plotting `StatsBase.Histogram`
|
||||
- allowing bins to be specified as `:sturges`, `:rice`, `:scott` or :fd
|
||||
- allow `normalization` to be specified as :density (for unequal bins) or :pdf (sum to 1)
|
||||
- add a `plotattr` function to access documentation for Plots attribute
|
||||
- add `fill_z` attribute for pyplot
|
||||
- add colorbar_title to plotlyjs
|
||||
- enable standalone window for plotlyjs
|
||||
- improved support for pgfplots, ticks rotation, clims, series_annotations
|
||||
- restore colorbars for GR
|
||||
- better axis labels for heatmap in GR
|
||||
- better marker sizes in GR
|
||||
- fix color representation in GR
|
||||
- update GR legend
|
||||
- fix image bug on GR
|
||||
- fix glvisualize dependencies
|
||||
- set dotted grid lines for pyplot
|
||||
- several improvements to inspectdr
|
||||
- improved tick positions for TimeType x axes
|
||||
- support for improved color gradient capability in PlotUtils
|
||||
- add a showlibrary recipe to display color libraries
|
||||
- add a showgradient recipe to display color gradients
|
||||
- add `vectorfield` as an alias for `quiver`
|
||||
- use `PlotUtils.adaptedgrid` for functions
|
||||
|
||||
|
||||
#### 0.9.5
|
||||
|
||||
- added dependency on PlotThemes
|
||||
- set_theme --> theme
|
||||
- remove Compat from REQUIRE
|
||||
- warning for DataFrames without StatsPlots
|
||||
- closeall exported and implemented for gr/pyplot
|
||||
- fix DateTime recipe
|
||||
- reset theme with theme(:none)
|
||||
- fix link_axes! for nested subplots
|
||||
- fix plotly lims for log scale
|
||||
|
||||
#### 0.9.4
|
||||
|
||||
- optimizations surrounding Subplot.series_list
|
||||
- better Atom support, support plotlyjs
|
||||
- gr:
|
||||
- gks_wstype defaults and gr_set_output
|
||||
- heatmap uses GR.drawimage
|
||||
- histogram2d puts NaN for zeros
|
||||
- improved support of NaN in heatmaps
|
||||
- rebuilt spy recipes to output scatters with marker_z set
|
||||
- deprecate png support in plotly... point to plotlyjs
|
||||
- fixes:
|
||||
- axis widen with lims set
|
||||
- reset_extrema, setxyz
|
||||
- bar plot widen
|
||||
- better tick padding
|
||||
- consistent tick rotation
|
||||
- consistent aspect_ratio
|
||||
- pyplot dpi
|
||||
- plotly horizontal bars
|
||||
- handle series attributes when combining subplots
|
||||
- gr images transposed
|
||||
- converted Date/DateTime to new type recipe approach for arrays
|
||||
- issues closed include: #505 #513 #479 #523 #526 #529
|
||||
|
||||
#### 0.9.3
|
||||
|
||||
- support pdf and eps in plotlyjs backend
|
||||
- allow curly after grid: `@layout [a b; grid(4,4){0.8h}]`
|
||||
- add_backend redesign
|
||||
|
||||
#### 0.9.2
|
||||
|
||||
- glvisualize backend (@SimonDanisch)
|
||||
- too much to list! ready for alpha testing
|
||||
- Volume and volume seriestype
|
||||
- Atom: support for PlotPane and proper gui display
|
||||
- gr:
|
||||
- clims
|
||||
- aspect ratio
|
||||
- pgfplots:
|
||||
- fixes for ticks, axes, and more
|
||||
- pyplot:
|
||||
- font families
|
||||
- colorbar guide
|
||||
- pixel marker
|
||||
- unicodeplots
|
||||
- basic support for shapes
|
||||
- improved add_backend
|
||||
- refactor of is_supported methods
|
||||
- element-wise type recipes (see https://github.com/tbreloff/Plots.jl/issues/460#issuecomment-248428908)
|
||||
- several other fixes/improvements
|
||||
|
||||
#### 0.9.1
|
||||
|
||||
- Pkg.dir --> dirname (@tkelman)
|
||||
- `axis = nothing` magic
|
||||
- fixes:
|
||||
- clim for line_z
|
||||
- sticks default range for log scale
|
||||
- rotate method
|
||||
- pyplot heatmap
|
||||
- spurious scale warnings
|
||||
- gr image/alpha
|
||||
- plotly.js path
|
||||
- orientation extrema
|
||||
- bar, reset orientation
|
||||
- switch transpose_z to use permutedims
|
||||
- skinny x/+ markers
|
||||
- ticks in pgfplots
|
||||
- eps in savefig (@anriseth)
|
||||
- add_backend convenience
|
||||
- type recipes for Date/DateTime (@maximsch2)
|
||||
- mirror attribute and twinx convenience
|
||||
- Axis.sp --> Axis.sps
|
||||
- recipe postprocessing for allowing aliases and magic args in recipe bodies
|
||||
|
||||
|
||||
|
||||
#### 0.9.0
|
||||
|
||||
- fixes to cycle
|
||||
- add back single function recipe: `plot!(cos)`
|
||||
- new axis formatter attribute... accepts functions to convert numbers to strings
|
||||
- fix for inset plots
|
||||
- GR:
|
||||
- fillrange fix
|
||||
- annotations fix
|
||||
- force double buffering in display
|
||||
|
||||
---
|
||||
|
||||
## 0.8
|
||||
|
||||
#### 0.8.2 (backported bug fixes for julia 0.4)
|
||||
|
||||
- plotly ticks fix
|
||||
- unicodeplots size fix
|
||||
- remove mkdir call in tests
|
||||
|
||||
#### 0.8.1
|
||||
|
||||
- manual drawing of axes/ticks/labels
|
||||
- get_ticks uses optimize_ticks and Showoff
|
||||
- changed PLOTS_DEFAULTS to be a global variable, not ENV key
|
||||
- parameterized Segments for pushing tuples
|
||||
- fix to axis extrema for Bool/nothing
|
||||
- GR:
|
||||
- manually draw 2D axes... fixes several issues and missing features
|
||||
- fontsize fix
|
||||
- PGFPlots: pass axis syle
|
||||
|
||||
#### 0.8.0
|
||||
|
||||
- added dependency on PlotUtils
|
||||
- BREAKING: removed DataFrames support (now in StatsPlots.jl)
|
||||
- BREAKING: removed boxplot/violin/density recipes (now in StatsPlots.jl)
|
||||
- GR:
|
||||
- inline iterm2 support
|
||||
- trisurface support
|
||||
- heatmap fix
|
||||
- PyPlot:
|
||||
- ijulia display fix
|
||||
- GLVisualize:
|
||||
- first try with shapes
|
||||
- iter_segments improvements
|
||||
- bar_width support
|
||||
- horizontal bars
|
||||
- improve tick display
|
||||
- better shape handling in pyplot, plotly
|
||||
- improved padding calcs
|
||||
- internal reorg of _plots method, add pipeline.jl
|
||||
|
||||
---
|
||||
|
||||
## 0.7
|
||||
|
||||
#### 0.7.5
|
||||
|
||||
- GR: LaTeX support
|
||||
- Changed docs url to juliaplots.github.io
|
||||
- added `contourf` seriestype
|
||||
- allow `plt[1]` to return first Subplot
|
||||
- allow `sp[1]` to return the first Series of the Subplot
|
||||
- `series[k]` now passes through to `series.d[k]`
|
||||
- allow calling `plot!(sp, ...)` to update a target Subplot
|
||||
- PyPlot: zorder fix
|
||||
- new DataFrames logic/recipe: more flexible/robust and allow Symbols for:
|
||||
- `(:fillrange, :line_z, :marker_z, :markersize, :ribbon, :weights, :xerror, :yerror)`
|
||||
- new `display_type` and `extra_kwargs` plot attributes
|
||||
- surface fix
|
||||
|
||||
#### 0.7.4
|
||||
|
||||
- added snooped precompiles, but left commented out
|
||||
- GR fixes: markersize, shapes, legends
|
||||
- fixes to recipes
|
||||
- turned on Appveyor
|
||||
|
||||
#### 0.7.3
|
||||
|
||||
- rebuild violin and boxplot recipes
|
||||
- "plot recipes"
|
||||
- `cgrad` method for easy color gradient creation
|
||||
- improvements to inset subplots
|
||||
- Segments and iter_segments for NaN-separated vectors
|
||||
- `bar` recipe now creates a `shape` series
|
||||
- writemime fix for Interact.jl
|
||||
- `link = :square` option
|
||||
- !!! set `shape` attributes with line/fill, NOT marker/markerstroke !!!
|
||||
- basic DPI support
|
||||
- moved chorddiagram to PlotRecipes
|
||||
- GR:
|
||||
- use temp files for img output
|
||||
- basic support for marker strokes and other marker fixes
|
||||
- PyPlot:
|
||||
- Switch to recipes for bar, histogram, histogram2d
|
||||
- GLVisualize
|
||||
- subplots
|
||||
- path/scatter and path3d/scatter3d
|
||||
- initial drawing of axes
|
||||
- many smaller fixes and improvements
|
||||
|
||||
#### 0.7.2
|
||||
|
||||
- line_z arg for multicolored line segments
|
||||
- pyplot
|
||||
- line_z (2d and 3d)
|
||||
- pushed all fig updates into display pipeline
|
||||
- remove native sticks/hline/vline in favor of recipes
|
||||
- unicodeplots cleanup, ijulia fixes, ascii canvas
|
||||
- `curves` series type
|
||||
- `iter_segments` iterator
|
||||
- moved arcdiagram out and into PlotRecipes (thanks @diegozea)
|
||||
- several other fixes/checks
|
||||
|
||||
#### 0.7.1
|
||||
|
||||
- inset (floating) subplots
|
||||
- change: when setting subplot/axis args from user recipes, they should apply only to their own subplot
|
||||
- trim for violin/boxplot
|
||||
- scatter3d recipe
|
||||
- removed plotly.js in favor of build.jl download
|
||||
- improvements/fixes to pgfplots backend
|
||||
- improvements/fixes to plotly/plotlyjs backends
|
||||
- titles are annotations and properly placed with title_position
|
||||
- hover attribute
|
||||
- shapes (almost)
|
||||
- scattergl
|
||||
- minimum perimeter logic in layout calc... fixed misaligned subplots
|
||||
- new clims attribute
|
||||
- more options for test_examples
|
||||
- GR refactor
|
||||
- added transparency
|
||||
- moved axis/grid logic out of series loop
|
||||
- generalized 3d and polar projections
|
||||
- renamed get_mod to Base.cycle
|
||||
- pyplot log scale fixes
|
||||
- PLOTS_DEFAULTS environment var processing
|
||||
- rename :ellipse to :circle, :ellipse is now an alias
|
||||
- supported args/types cleanup
|
||||
- seriestype dependency methods and `@deps` macro
|
||||
- bbox `h_anchor`/`v_anchor`
|
||||
- new axis arg: `:link` is a list of subplots to link axes with
|
||||
- cleanup/simplification of glvisualize backend
|
||||
|
||||
|
||||
#### 0.7.0
|
||||
|
||||
- Check out [the summary](http://juliaplots.github.io/plots_v0.7/)
|
||||
- Revamped and simplified internals
|
||||
- [Recipes, recipes, recipes](https://github.com/JuliaPlots/RecipesBase.jl/issues/6)
|
||||
- [Layouts and Subplots](https://github.com/tbreloff/Plots.jl/issues/60)
|
||||
- DataFrames is loaded automatically when installed
|
||||
- Overhaul to GroupBy mechanic (now offloads to a recipe)
|
||||
- Replaced much of the argument processing with recipes
|
||||
- Added series recipes, and began to strip down un-needed backend code. Some recipes:
|
||||
- line, step, sticks, bar, histogram, histogram2d, boxplot, violin, quiver, errorbars, density, ohlc
|
||||
- Added `@shorthands` and `@userplot` macros for recipe convenience
|
||||
- Better handling of errorbars and ribbons
|
||||
- New Axis type
|
||||
- Tracks extrema and discrete values
|
||||
- New `link_axes` functionality
|
||||
- `linetype` has been renamed `seriestype` (the alias is reversed)
|
||||
- Many fixes and huge cleanup in GR
|
||||
- Brand new subplot layout mechanics:
|
||||
- `@layout` macro
|
||||
- AbstractLayout, Subplot, GridLayout, and everything related
|
||||
- Added dependency on Measures.jl
|
||||
- Computations of axis/guide sizes and precise positioning
|
||||
- Refactored and compartmentalized default dictionaries for attributes
|
||||
- Deprecated Gadfly and Immerse backends
|
||||
- Added `series_annotations` attribute (previously that functionality was merged with `annotations`, which are not series-specific)
|
||||
- Removed `axis` attribute... currently not supporting twin (right) y axes
|
||||
- Check for `ENV["PLOTS_USE_ATOM_PLOTPANE"]` and default to false
|
||||
- Improved backend interface to reduce redundant code. Template updated.
|
||||
- Added `html_output_format`, primarily for choosing between png and svg output in IJulia.
|
||||
- Partial support of Julia v0.5
|
||||
- Switched testing to dump reference images to JuliaPlots/PlotReferenceImages.jl
|
||||
- Moved docs-specific code to new JuliaPlots/PlotDocs.jl
|
||||
- Moved example list from ExamplePlots into Plots.
|
||||
- Added several examples and improved others.
|
||||
- Many other smaller changes and bug fixes.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Version 0.6
|
||||
|
||||
#### 0.6.2
|
||||
|
||||
- `linewidth` fixes
|
||||
- `markershape` fix
|
||||
- converted center calc to centroid for shapes
|
||||
- new dependency on [RecipesBase](https://github.com/JuliaPlots/RecipesBase.jl)
|
||||
- REQUIRE upper limit for RecipesBase: 0.0.1
|
||||
- GR fixes/improvements (@jheinen)
|
||||
- support `zlims`, `bins`
|
||||
- allow Plots colormaps
|
||||
- other bug fixes
|
||||
- native image support
|
||||
- PGFPlots fixes/improvements (@pkofod)
|
||||
- DataFrames are handled by recipes
|
||||
- Plotly: zaxis, tick rotation, 3d axis fix
|
||||
- Improvements in handling discrete data
|
||||
- Support for image display
|
||||
- `arrow` keyword and support for adding arrows to paths
|
||||
- changed quiver recipe to use arrows
|
||||
- Bug fixes for boxplots, heatmaps, and more
|
||||
|
||||
#### 0.6.1
|
||||
|
||||
- `rotation` keyword
|
||||
- improved supported graphs
|
||||
- subplot bug fix
|
||||
|
||||
#### 0.6.0
|
||||
|
||||
- `apply_series_recipe` framework for built-in recipes
|
||||
- [boxplot/violin recipes](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/boxplot.ipynb)
|
||||
- [errorbar/ribbon recipes](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/errorbars.ipynb)
|
||||
- [quiver recipe](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/quiver.ipynb)
|
||||
- `polar` coordinates
|
||||
- better support for shapes and custom polygons (see [batman](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/batman.ipynb))
|
||||
- z-axis keywords
|
||||
- 3D indexing overhaul: `push!`, `append!` support
|
||||
- matplotlib colormap constants (`:inferno` is the new default colormap for Plots)
|
||||
- `const KW = Dict{Symbol,Any}` used in place of splatting in many places
|
||||
- png generation for plotly backend using wkhtmltoimage
|
||||
- `normalize` and `weights` keywords
|
||||
- background/foreground subcategories for fine-tuning of looks
|
||||
- `add_theme`/`set_theme` and ggplot2 theme (see [this issue](https://github.com/tbreloff/Plots.jl/issues/201))
|
||||
- `PLOTS_DEFAULT_BACKEND` environment variable
|
||||
- `barh` linetype
|
||||
- support for non-gridded surfaces with pyplot's trisurface
|
||||
- pyplot surface zcolor
|
||||
- internal refactor of supported.jl
|
||||
- `wrap` method to bypass input processing
|
||||
- `translate`, `scale` and `rotate` methods for coordinates and shapes
|
||||
- and many more minor fixes and improvements
|
||||
|
||||
---
|
||||
|
||||
## Version 0.5
|
||||
|
||||
#### 0.5.4
|
||||
|
||||
- old heatmaps have been renamed to hist2d, and true heatmaps implemented (see https://github.com/tbreloff/Plots.jl/issues/147)
|
||||
- lots of reorganization and redesign of the internals
|
||||
- lots of renaming to keep to conventions: AbstractPlot, AbstractBackend, etc
|
||||
- initial redesign of layouts
|
||||
- integration with Atom PlotPane
|
||||
- arc diagram and chord diagram (thanks to @diegozea: see https://github.com/tbreloff/Plots.jl/issues/163)
|
||||
- work on GR, GLVisualize, and PGFPlots backends (thanks @jheinen @dlfivefifty @pkofod)
|
||||
- improvements to Plotly setup (thanks @spencerlyon2)
|
||||
- overhaul to series creation logic and groupby mechanic
|
||||
- replace Dict with `typealias KW Dict{Symbol,Any}` in many places, also replacing keyword arg splatting
|
||||
- new `shape` linetype for plotting polygons in plot-coordinates (see https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/batman.ipynb)
|
||||
- many other fixes
|
||||
|
||||
#### 0.5.3
|
||||
|
||||
- `@gif` macro with `every`/`when` syntax
|
||||
- bezier curves and other graph drawing helpers
|
||||
- added FixedSizeArrays dependency with relevant functionality
|
||||
- merged lots of improvements to GR (thanks @jheinen)
|
||||
- `overwrite_figure`/`reuse` arg for reusing the same figure window
|
||||
- deprecated Qwt, Winston, and Bokeh backends
|
||||
- improved handling of 3D inputs (call `z=rand(10,10); surface(z)` for example)
|
||||
- fix IJulia display issue
|
||||
- lots of progress on PlotlyJS backend
|
||||
- and many other changes and fixes...
|
||||
|
||||
#### 0.5.2
|
||||
|
||||
- Added [GR.jl](https://github.com/jheinen/GR.jl) as a backend (unfinished but functional) All credit to @jheinen
|
||||
- Set defaults within backend calls (i.e. `gadfly(legend=false)`)
|
||||
- `abline!`; also extrema allows plotting functions without giving x (i.e. `plot(cos, 0, 10); plot!(sin)`) @pkofod @joshday
|
||||
- Integration with [PlotlyJS.jl](https://github.com/spencerlyon2/PlotlyJS.jl) for using Plotly inside a Blink window @spencerlyon2
|
||||
- The Plotly backend has been split into my built-in version (`plotly()`) and @spencerlyon2's backend (`plotlyjs()`)
|
||||
- Revamped backend setup code for easily adding new backends
|
||||
- New docs (WIP) at http://juliaplots.github.io/
|
||||
- Overhaul to `:legend` keyword (see https://github.com/tbreloff/Plots.jl/issues/135)
|
||||
- New dependency on Requires, allows auto-loading of DataFrames support
|
||||
- Support for plotting lists of Tuples and FixedSizeArrays
|
||||
- new `@animate` macro for super simple animations (see https://github.com/tbreloff/Plots.jl/issues/111#issuecomment-181515616)
|
||||
- allow Function for `:fillrange` and `zcolor` arguments (for example: `scatter(sin, 0:10, marker=15, fill=(cos,0.4), zcolor=sin)`)
|
||||
- allow vectors of PlotText without x/y coords (for example: `scatter(rand(10), m=20, ann=map(text, 1:10))`)
|
||||
- Lots and lots of fixes
|
||||
|
||||
#### 0.5.1
|
||||
|
||||
#### 0.5.0
|
||||
|
||||
- `with` function for temporary defaults
|
||||
- contours
|
||||
- basic 3D plotting
|
||||
- preliminary support for Bokeh
|
||||
- `stroke` and `brush` for more fine-tuned control over visuals
|
||||
- smarter "magic" arguments: `line`, `marker`
|
||||
@@ -0,0 +1,76 @@
|
||||
name = "Plots"
|
||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
author = ["Tom Breloff (@tbreloff)"]
|
||||
version = "1.10.4"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
|
||||
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
|
||||
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
|
||||
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
|
||||
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
|
||||
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
|
||||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
|
||||
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
|
||||
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
|
||||
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
|
||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
|
||||
RecipesPipeline = "01d81517-befc-4cb6-b9ec-a95719d0359c"
|
||||
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
|
||||
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
|
||||
Scratch = "6c6a2e73-6563-6170-7368-637461726353"
|
||||
Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
|
||||
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
|
||||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
|
||||
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
|
||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||
|
||||
[compat]
|
||||
Contour = "0.5"
|
||||
FFMPEG = "0.2, 0.3, 0.4"
|
||||
FixedPointNumbers = "0.6, 0.7, 0.8"
|
||||
GR = "0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54"
|
||||
GeometryBasics = "0.2, 0.3.1"
|
||||
JSON = "0.21, 1"
|
||||
Latexify = "0.14"
|
||||
Measures = "0.3"
|
||||
NaNMath = "0.3"
|
||||
PlotThemes = "2"
|
||||
PlotUtils = "1"
|
||||
RecipesBase = "1"
|
||||
RecipesPipeline = "0.3"
|
||||
Reexport = "0.2, 1.0"
|
||||
Requires = "1"
|
||||
Scratch = "1"
|
||||
Showoff = "0.3.1"
|
||||
StatsBase = "0.32, 0.33"
|
||||
julia = "1.5"
|
||||
|
||||
[extras]
|
||||
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
|
||||
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
|
||||
Gtk = "4c0ca9eb-093a-5379-98c5-f87ac0bbbf44"
|
||||
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
|
||||
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
|
||||
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
||||
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
|
||||
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
|
||||
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
|
||||
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
|
||||
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
|
||||
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
|
||||
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
|
||||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
|
||||
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
|
||||
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
|
||||
|
||||
[targets]
|
||||
test = ["Distributions", "FileIO", "Gtk", "ImageMagick", "Images", "LibGit2", "OffsetArrays", "PGFPlotsX", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]
|
||||
@@ -1,266 +1,33 @@
|
||||
# Plots
|
||||
|
||||
[](https://travis-ci.org/tbreloff/Plots.jl)
|
||||
[gh-ci-img]: https://github.com/JuliaPlots/Plots.jl/workflows/ci/badge.svg?branch=master
|
||||
[gh-ci-url]: https://github.com/JuliaPlots/Plots.jl/actions?query=workflow%3Aci
|
||||
|
||||
#### Author: Thomas Breloff (@tbreloff)
|
||||
[pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/P/Plots.svg
|
||||
[pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html
|
||||
|
||||
Plotting interface and wrapper for several plotting packages.
|
||||
[gitter-img]: https://badges.gitter.im/tbreloff/Plots.jl.svg
|
||||
[gitter-url]: https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
|
||||
Please add wishlist items, bugs, or any other comments/questions to the issues list.
|
||||
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
|
||||
[docs-url]: http://docs.juliaplots.org/latest/
|
||||
|
||||
## Examples for each implemented backend:
|
||||
[![][gh-ci-img]][gh-ci-url]
|
||||
[![][pkgeval-img]][pkgeval-url]
|
||||
[](https://julialang.zulipchat.com/#narrow/stream/236493-plots)
|
||||
[![][docs-img]][docs-url]
|
||||
[](https://codecov.io/gh/JuliaPlots/Plots.jl)
|
||||
|
||||
- [Qwt.jl](docs/qwt_examples.md)
|
||||
- [Gadfly.jl](docs/gadfly_examples.md)
|
||||
- [UnicodePlots.jl](docs/unicodeplots_examples.md)
|
||||
#### Created by Tom Breloff (@tbreloff)
|
||||
|
||||
## Installation
|
||||
|
||||
First, clone the package
|
||||
|
||||
```julia
|
||||
Pkg.clone("https://github.com/tbreloff/Plots.jl.git")
|
||||
```
|
||||
|
||||
then get any plotting packages you need (obviously, you should get at least one backend):
|
||||
|
||||
```julia
|
||||
Pkg.add("Gadfly") # [optional]
|
||||
Pkg.clone("https://github.com/tbreloff/Qwt.jl.git") # [optional] requires pyqt and pyqwt
|
||||
Pkg.add("UnicodePlots") # [optional]
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
Load it in. The underlying plotting backends are not imported until `plotter()` is called (which happens
|
||||
on your first call to `plot` or `subplot`). This means that you don't need any backends to be installed when you call `using Plots`.
|
||||
Plots will try to figure out a good default backend for you automatically based on what backends are installed.
|
||||
|
||||
```julia
|
||||
using Plots
|
||||
```
|
||||
|
||||
Do a plot in Gadfly, then save a png:
|
||||
|
||||
```julia
|
||||
gadfly!()
|
||||
plot(rand(10,2); marker = :rect) # this will bring up a browser window with the plot, set show=false if you don't want that
|
||||
savepng(Plots.IMG_DIR * "gadfly1.png")
|
||||
```
|
||||
|
||||
which saves:
|
||||
|
||||

|
||||
|
||||
See the examples pages for lots of ways to plot in every supported backend.
|
||||
|
||||
## API
|
||||
|
||||
Call `plotter!(backend::Symbol)` or the shorthands (`gadfly!()`, `qwt!()`, `unicodeplots!()`, etc) to set the current plotting backend.
|
||||
Subsequent commands are converted into the relevant plotting commands for that package:
|
||||
|
||||
```julia
|
||||
gadfly!()
|
||||
plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
|
||||
qwt!()
|
||||
plot(1:10) # this effectively calls `Qwt.plot(1:10)`
|
||||
```
|
||||
|
||||
Use `plot` to create a new plot object, and `plot!` to add to an existing one:
|
||||
|
||||
```julia
|
||||
plot(args...; kw...) # creates a new plot window, and sets it to be the `currentPlot`
|
||||
plot!(args...; kw...) # adds to the `currentPlot`
|
||||
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
|
||||
```
|
||||
|
||||
Now that you know which plot object you're updating (new, current, or other), I'll leave it off for simplicity.
|
||||
Here are some various args to supply, and the implicit mapping (AVec == AbstractVector and AMat == AbstractMatrix):
|
||||
|
||||
```julia
|
||||
# one line... x = 1:length(y)
|
||||
plot(y::AVec; kw...)
|
||||
|
||||
# one line (will assert length(x) == length(y))
|
||||
plot(x::AVec, y::AVec; kw...)
|
||||
|
||||
# multiple lines (one per column of x), all sharing x = 1:size(y,1)
|
||||
plot(y::AMat; kw...)
|
||||
|
||||
# multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1))
|
||||
plot(x::AVec, y::AMat; kw...)
|
||||
|
||||
# multiple lines (one per column of x/y... will assert size(x) == size(y))
|
||||
plot(x::AMat, y::AMat; kw...)
|
||||
|
||||
# one line, map function for range [xmin,xmax]
|
||||
plot(f::Function, xmin::Real, xmax::Real; kw...)
|
||||
|
||||
# multiple lines, map functions for range [xmin,xmax]
|
||||
plot(f::AVec{Function}, xmin::Real, xmax::Real; kw...)
|
||||
|
||||
# parametric plot... x = fx(u), y = fy(u)
|
||||
plot(fx::Function, fy::Function, umin::Real, umax::Real; kw...)
|
||||
|
||||
# one line, y = f(x)... can swap x and f
|
||||
plot(x::AVec, f::Function; kw...)
|
||||
|
||||
# multiple lines, yᵢⱼ = f(xᵢⱼ)... can swap f and x
|
||||
plot(x::AMat, f::Function; kw...)
|
||||
|
||||
# multiple lines, yᵢⱼ = fⱼ(xᵢ)
|
||||
plot(x::AVec, fs::AVec{Function}; kw...)
|
||||
|
||||
# multiple lines, each with x = 1:length(y[i])
|
||||
plot(y::AVec{AVec}; kw...)
|
||||
|
||||
# multiple lines, will assert length(x) == length(y[i])
|
||||
plot(x::AVec, y::AVec{AVec}; kw...)
|
||||
|
||||
# multiple lines, will assert length(x[i]) == length(y[i])
|
||||
plot(x::AVec{AVec}, y::AVec{AVec}; kw...)
|
||||
|
||||
# n lines, all empty (for updating plots)
|
||||
plot(n::Integer; kw...)
|
||||
|
||||
# TODO: DataFrames, categorical values
|
||||
```
|
||||
|
||||
With `subplot`, create multiple plots at once, with flexible layout options:
|
||||
|
||||
```julia
|
||||
y = rand(100,3)
|
||||
subplot(y; n = 3) # create an automatic grid, and let it figure out the shape
|
||||
subplot(y; n = 3, nr = 1) # create an automatic grid, but fix the number of rows
|
||||
subplot(y; n = 3, nc = 1) # create an automatic grid, but fix the number of columns
|
||||
subplot(y; layout = [1, 2]) # explicit layout. Lists the number of plots in each row
|
||||
```
|
||||
|
||||
__Tip__: You can call `subplot!(args...; kw...)` to add to an existing subplot.
|
||||
|
||||
__Tip__: Calling `subplot!` on a `Plot` object, or `plot!` on a `Subplot` object will throw an error.
|
||||
|
||||
Shorthands:
|
||||
|
||||
```julia
|
||||
scatter(args...; kw...) = plot(args...; kw..., linetype = :none, marker = :hexagon)
|
||||
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :none, marker = :hexagon)
|
||||
bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
|
||||
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
|
||||
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
|
||||
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
|
||||
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
|
||||
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
|
||||
```
|
||||
|
||||
Some keyword arguments you can set:
|
||||
|
||||
```
|
||||
axis # :left or :right
|
||||
color # can be a string ("red") or a symbol (:red) or a ColorsTypes.jl
|
||||
# Colorant (RGB(1,0,0)) or :auto (which lets the package pick)
|
||||
label # string or symbol, applies to that line, may go in a legend
|
||||
width # width of a line
|
||||
linetype # :line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar
|
||||
linestyle # :solid, :dash, :dot, :dashdot, :dashdotdot
|
||||
marker # :none, :ellipse, :rect, :diamond, :utriangle, :dtriangle,
|
||||
# :cross, :xcross, :star1, :star2, :hexagon
|
||||
markercolor # same choices as `color`, or :match will set the color to be the same as `color`
|
||||
markersize # size of the marker
|
||||
nbins # number of bins for heatmap/hexbin and histograms
|
||||
heatmap_c # color cutoffs for Qwt heatmaps
|
||||
fillto # fillto value for area plots
|
||||
title # string or symbol, title of the plot
|
||||
xlabel # string or symbol, label on the bottom (x) axis
|
||||
ylabel # string or symbol, label on the left (y) axis
|
||||
yrightlabel # string or symbol, label on the right (y) axis
|
||||
reg # true or false, add a regression line for each line
|
||||
size # (Int,Int), resize the enclosing window
|
||||
pos # (Int,Int), move the enclosing window to this position
|
||||
windowtitle # string or symbol, set the title of the enclosing windowtitle
|
||||
screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
||||
show # true or false, show the plot (in case you don't want the window to pop up right away)
|
||||
```
|
||||
|
||||
Note that not every backend supports all options.
|
||||
|
||||
If you don't include a keyword argument, these are the defaults:
|
||||
|
||||
```
|
||||
axis = :left
|
||||
color = :auto
|
||||
label = automatically generated (y1, y2, ...., or y1 (R), y2 (R) for the right axis)
|
||||
width = 1
|
||||
linetype = :line
|
||||
linestype = :solid
|
||||
marker = :none
|
||||
markercolor = :match
|
||||
markersize = 3
|
||||
nbins = 100
|
||||
heatmap_c = (0.15, 0.5)
|
||||
fillto = nothing
|
||||
title = ""
|
||||
xlabel = ""
|
||||
ylabel = ""
|
||||
yrightlabel = ""
|
||||
reg = false
|
||||
size = (800,600)
|
||||
pos = (0,0)
|
||||
windowtitle = ""
|
||||
screen = 1
|
||||
show = true
|
||||
```
|
||||
|
||||
__Tip__: You can see the default value for a given argument with `plotDefault(arg::Symbol)`, and set the default value with `plotDefault!(arg::Symbol, value)`
|
||||
|
||||
__Tip__: When plotting multiple lines, you can give every line the same trait by using the singular, or add an "s" to pluralize.
|
||||
(yes I know it's not gramatically correct, but it's easy to use and implement)
|
||||
|
||||
```julia
|
||||
# Note: The same width is applied to both lines, whereas
|
||||
# each line gets different color and axis.
|
||||
plot(rand(100,2); colors = [:red, RGB(.5,.5,0)],
|
||||
axiss = [:left, :right],
|
||||
width = 5)
|
||||
```
|
||||
|
||||
# TODO
|
||||
|
||||
- [x] Plot vectors/matrices/functions
|
||||
- [ ] Plot DataFrames
|
||||
- [ ] Scales
|
||||
- [ ] Categorical Inputs (strings, etc... for hist, bar? or can split one series into multiple?)
|
||||
- [ ] Custom markers
|
||||
- [ ] Special plots (boxplot, ohlc?)
|
||||
- [x] Subplots
|
||||
- [x] Histograms
|
||||
- [ ] 3D plotting
|
||||
- [ ] Scenes/Drawing
|
||||
- [ ] Graphs
|
||||
- [ ] Interactivity (GUIs)
|
||||
- [x] Gadfly.jl
|
||||
- [ ] PyPlot.jl
|
||||
- [ ] Winston.jl
|
||||
- [ ] Gaston.jl
|
||||
- [ ] GLPlot.jl
|
||||
- [x] Qwt.jl
|
||||
- [ ] Bokeh.jl
|
||||
- [ ] Plotly.jl
|
||||
- [ ] GoogleCharts.jl
|
||||
- [ ] Vega.jl
|
||||
- [ ] PLplot.jl
|
||||
- [ ] TextPlots.jl
|
||||
- [ ] ASCIIPlots.jl
|
||||
- [ ] Sparklines.jl
|
||||
- [x] UnicodePlots.jl
|
||||
- [ ] Hinton.jl
|
||||
- [ ] ImageTerm.jl
|
||||
- [ ] GraphViz.jl
|
||||
- [ ] TikzGraphs.jl
|
||||
- [ ] GraphLayout.jl
|
||||
|
||||
# More information on backends (both supported and unsupported)
|
||||
|
||||
See the wiki at: https://github.com/JuliaPlot/juliaplot_docs/wiki
|
||||
#### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people)
|
||||
|
||||
Plots is a plotting API and toolset. My goals with the package are:
|
||||
|
||||
- **Powerful**. Do more with less. Complex visualizations become easy.
|
||||
- **Intuitive**. Stop reading so much documentation. Commands should "just work".
|
||||
- **Concise**. Less code means fewer mistakes and more efficient development/analysis.
|
||||
- **Flexible**. Produce your favorite plots from your favorite package, but quicker and simpler.
|
||||
- **Consistent**. Don't commit to one graphics package, use the same code everywhere.
|
||||
- **Lightweight**. Very few dependencies.
|
||||
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
environment:
|
||||
matrix:
|
||||
- JULIAVERSION: "julialang/bin/winnt/x86/0.3/julia-0.3-latest-win32.exe"
|
||||
- JULIAVERSION: "julialang/bin/winnt/x64/0.3/julia-0.3-latest-win64.exe"
|
||||
- JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
|
||||
- JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /release-.*/
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
on_build_failure: false
|
||||
on_build_status_changed: false
|
||||
|
||||
install:
|
||||
# Download most recent Julia Windows binary
|
||||
- ps: (new-object net.webclient).DownloadFile(
|
||||
$("http://s3.amazonaws.com/"+$env:JULIAVERSION),
|
||||
"C:\projects\julia-binary.exe")
|
||||
# Run installer silently, output to C:\projects\julia
|
||||
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
|
||||
|
||||
build_script:
|
||||
# Need to convert from shallow to complete for Pkg.clone to work
|
||||
- IF EXIST .git\shallow (git fetch --unshallow)
|
||||
- C:\projects\julia\bin\julia -e "versioninfo();
|
||||
Pkg.clone(pwd(), \"Plots\"); Pkg.build(\"Plots\")"
|
||||
|
||||
test_script:
|
||||
- C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"Plots\")"
|
||||
@@ -0,0 +1,5 @@
|
||||
[deps]
|
||||
BenchmarkCI = "20533458-34a3-403d-a444-e18f38190b5b"
|
||||
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
|
||||
PkgBenchmark = "32113eaa-f34f-5b0d-bd6c-c81e245fc73d"
|
||||
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
@@ -0,0 +1,10 @@
|
||||
using BenchmarkTools
|
||||
using Plots
|
||||
|
||||
const SUITE = BenchmarkGroup()
|
||||
julia_cmd = split(get(ENV, "TESTCMD", Base.JLOptions().julia_bin))
|
||||
|
||||
SUITE["load_plot_display"] = @benchmarkable run(`$julia_cmd --startup-file=no --project -e 'using Plots; display(plot(1:0.1:10, sin.(1:0.1:10)))'`)
|
||||
SUITE["load"] = @benchmarkable run(`$julia_cmd --startup-file=no --project -e 'using Plots'`)
|
||||
SUITE["plot"] = @benchmarkable p = plot(1:0.1:10, sin.(1:0.1:10)) samples=1 evals=1
|
||||
SUITE["display"] = @benchmarkable display(p) setup=(p = plot(1:0.1:10, sin.(1:0.1:10))) samples=1 evals=1
|
||||
@@ -0,0 +1,10 @@
|
||||
ignore:
|
||||
- "src/backends/inspectdr.jl"
|
||||
- "src/backends/orca.jl"
|
||||
- "src/backends/pgfplots.jl"
|
||||
- "src/backends/plotly.jl"
|
||||
- "src/backends/plotlyjs.jl"
|
||||
- "src/backends/pyplot.jl"
|
||||
- "src/backends/web.jl"
|
||||
- "src/fileio.jl"
|
||||
- "src/ijulia.jl"
|
||||
@@ -0,0 +1,390 @@
|
||||
const __bodyfunction__ = Dict{Method,Any}()
|
||||
|
||||
# Find keyword "body functions" (the function that contains the body
|
||||
# as written by the developer, called after all missing keyword-arguments
|
||||
# have been assigned values), in a manner that doesn't depend on
|
||||
# gensymmed names.
|
||||
# `mnokw` is the method that gets called when you invoke it without
|
||||
# supplying any keywords.
|
||||
function __lookup_kwbody__(mnokw::Method)
|
||||
function getsym(arg)
|
||||
isa(arg, Symbol) && return arg
|
||||
@assert isa(arg, GlobalRef)
|
||||
return arg.name
|
||||
end
|
||||
|
||||
f = get(__bodyfunction__, mnokw, nothing)
|
||||
if f === nothing
|
||||
fmod = mnokw.module
|
||||
# The lowered code for `mnokw` should look like
|
||||
# %1 = mkw(kwvalues..., #self#, args...)
|
||||
# return %1
|
||||
# where `mkw` is the name of the "active" keyword body-function.
|
||||
ast = Base.uncompressed_ast(mnokw)
|
||||
if isa(ast, Core.CodeInfo) && length(ast.code) >= 2
|
||||
callexpr = ast.code[end-1]
|
||||
if isa(callexpr, Expr) && callexpr.head == :call
|
||||
fsym = callexpr.args[1]
|
||||
if isa(fsym, Symbol)
|
||||
f = getfield(fmod, fsym)
|
||||
elseif isa(fsym, GlobalRef)
|
||||
if fsym.mod === Core && fsym.name === :_apply
|
||||
f = getfield(mnokw.module, getsym(callexpr.args[2]))
|
||||
elseif fsym.mod === Core && fsym.name === :_apply_iterate
|
||||
f = getfield(mnokw.module, getsym(callexpr.args[3]))
|
||||
else
|
||||
f = getfield(fsym.mod, fsym.name)
|
||||
end
|
||||
else
|
||||
f = missing
|
||||
end
|
||||
else
|
||||
f = missing
|
||||
end
|
||||
else
|
||||
f = missing
|
||||
end
|
||||
__bodyfunction__[mnokw] = f
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
function _precompile_()
|
||||
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:label, :blank),Tuple{Symbol,Bool}},Type{EmptyLayout}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:label, :width, :height),Tuple{Symbol,Symbol,Length{:pct,Float64}}},Type{EmptyLayout}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,),Tuple{GridLayout}},Type{Subplot},GRBackend})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,),Tuple{GridLayout}},Type{Subplot},PlotlyBackend})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,),Tuple{Subplot{GRBackend}}},Type{Subplot},GRBackend})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,),Tuple{Subplot{PlotlyBackend}}},Type{Subplot},PlotlyBackend})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights),Tuple{Bool,Array{Int64,1}}},typeof(_make_hist),Tuple{Array{Float64,1}},Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights),Tuple{Bool,Nothing}},typeof(_make_hist),Tuple{Array{Float64,1},Array{Float64,1}},Int64})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights),Tuple{Bool,Nothing}},typeof(_make_hist),Tuple{Array{Float64,1}},Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:flip,),Tuple{Bool}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,),Tuple{Symbol}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,),Tuple{typeof(datetimeformatter)}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims),Tuple{Bool,Tuple{Float64,Float64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims, :flip),Tuple{Bool,Tuple{Float64,Float64},Bool}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid,),Tuple{Bool}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:gridlinewidth, :grid, :gridalpha, :gridstyle, :foreground_color_grid),Tuple{Int64,Bool,Float64,Symbol,RGBA{Float64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guide,),Tuple{String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims, :flip, :ticks, :guide),Tuple{Tuple{Int64,Int64},Bool,StepRange{Int64,Int64},String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,),Tuple{Tuple{Float64,Float64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,),Tuple{Tuple{Int64,Float64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,),Tuple{Tuple{Int64,Int64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:rotation,),Tuple{Int64}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:scale, :guide),Tuple{Symbol,String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,),Tuple{Nothing}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,),Tuple{UnitRange{Int64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(default)),NamedTuple{(:titlefont, :legendfontsize, :guidefont, :tickfont, :guide, :framestyle, :yminorgrid),Tuple{Tuple{Int64,String},Int64,Tuple{Int64,Symbol},Tuple{Int64,Symbol},String,Symbol,Bool}},typeof(default)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(gr_polyline),Array{Int64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(gr_polyline),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(gr_polyline),StepRange{Int64,Int64},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(gr_polyline),UnitRange{Int64},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(gr_polyline),UnitRange{Int64},UnitRange{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(heatmap)),Any,typeof(heatmap),Any,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(hline!)),Any,typeof(hline!),Any})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(lens!)),Any,typeof(lens!),Any,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype),Tuple{Float64,Symbol}},typeof(plot!),Array{GeometryBasics.Point{2,Float64},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype),Tuple{Float64,Symbol}},typeof(plot!),Plot{GRBackend},Array{GeometryBasics.Point{2,Float64},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:annotation,),Tuple{Array{Tuple{Int64,Float64,PlotText},1}}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype),Tuple{Tuple{Int64,Symbol,Float64,Array{Symbol,2}},Symbol}},typeof(plot!),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color),Tuple{Int64,Symbol}},typeof(plot!),Function,Float64,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color),Tuple{Int64,Symbol}},typeof(plot!),Plot{GRBackend},Function,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype),Tuple{Tuple{Int64,Float64,Symbol},Array{Any,1},Symbol}},typeof(plot!),Plot{GRBackend},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype),Tuple{Tuple{Int64,Float64,Symbol},Array{Any,1},Symbol}},typeof(plot!),Plot{PlotlyBackend},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype),Tuple{Tuple{Int64,Float64,Symbol},Array{Any,1},Symbol}},typeof(plot!),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype),Tuple{Int64,Symbol,Symbol}},typeof(plot!),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset),Tuple{Symbol,Tuple{Int64,BoundingBox{Tuple{Length{:w,Float64},Length{:h,Float64}},Tuple{Length{:w,Float64},Length{:h,Float64}}}}}},typeof(plot!),Array{Int64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset),Tuple{Symbol,Tuple{Int64,BoundingBox{Tuple{Length{:w,Float64},Length{:h,Float64}},Tuple{Length{:w,Float64},Length{:h,Float64}}}}}},typeof(plot!),Plot{GRBackend},Array{Int64,1},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset),Tuple{Symbol,Tuple{Int64,BoundingBox{Tuple{Length{:w,Float64},Length{:h,Float64}},Tuple{Length{:w,Float64},Length{:h,Float64}}}}}},typeof(plot!),Plot{PlotlyBackend},Array{Int64,1},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype,),Tuple{Symbol}},typeof(plot!),Array{Int64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:title,),Tuple{String}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:w,),Tuple{Int64}},typeof(plot!),Plot{GRBackend},Array{Float64,1},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:xgrid,),Tuple{Tuple{Symbol,Symbol,Int64,Symbol,Float64}}},typeof(plot!),Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis,),Tuple{Tuple{String,Symbol}}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Stroke},Array{Float64,1},String,Symbol}},typeof(plot!),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Stroke},Array{Float64,1},String,Symbol}},typeof(plot!),Plot{GRBackend},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Stroke},Array{Float64,1},String,Symbol}},typeof(plot!),Plot{PlotlyBackend},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:annotations, :leg),Tuple{Tuple{Int64,Float64,PlotText},Bool}},typeof(plot),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:aspect_ratio, :seriestype),Tuple{Int64,Symbol}},typeof(plot),Array{String,1},Array{String,1},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:bins, :weights, :seriestype),Tuple{Symbol,Array{Int64,1},Symbol}},typeof(plot),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:color, :line, :marker),Tuple{Array{Symbol,2},Tuple{Symbol,Int64},Tuple{Array{Symbol,2},Int64,Float64,Stroke}}},typeof(plot),Array{Array{T,1} where T,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:connections, :seriestype),Tuple{Tuple{Array{Int64,1},Array{Int64,1},Array{Int64,1}},Symbol}},typeof(plot),Array{Int64,1},Array{Int64,1},Vararg{Array{Int64,1},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill, :seriestype),Tuple{Bool,Symbol}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:framestyle, :title, :color, :layout, :label, :markerstrokewidth, :ticks, :seriestype),Tuple{Array{Symbol,2},Array{String,2},Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}},Int64,String,Int64,UnitRange{Int64},Symbol}},typeof(plot),Array{Array{Float64,1},1},Array{Array{Float64,1},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:grid, :title),Tuple{Tuple{Symbol,Symbol,Symbol,Int64,Float64},String}},typeof(plot),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:lab, :w, :palette, :fill, :α),Tuple{String,Int64,PlotUtils.ContinuousColorGradient,Int64,Float64}},typeof(plot),StepRange{Int64,Int64},Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label, :title, :xlabel, :linewidth, :legend),Tuple{Array{String,2},String,String,Int64,Symbol}},typeof(plot),Array{Function,1},Float64,Vararg{Float64,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label,),Tuple{Array{String,2}}},typeof(plot),Array{AbstractArray{Float64,1},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :group, :linetype, :linecolor),Tuple{GridLayout,Array{String,1},Array{Symbol,2},Symbol}},typeof(plot),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha),Tuple{Tuple{Int64,Int64},String,Int64,Float64}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha),Tuple{Tuple{Int64,Int64},String,Int64,Float64}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :link),Tuple{Int64,Symbol}},typeof(plot),Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :link),Tuple{Int64,Symbol}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :palette, :bg_inside),Tuple{Int64,Array{PlotUtils.ContinuousColorGradient,2},Array{Symbol,2}}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :t, :leg, :ticks, :border),Tuple{GridLayout,Array{Symbol,2},Bool,Nothing,Symbol}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :title, :titlelocation, :left_margin, :bottom_margin, :xrotation),Tuple{GridLayout,Array{String,2},Symbol,Array{Length{:mm,Float64},2},Length{:mm,Float64},Int64}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xlims),Tuple{GridLayout,Tuple{Int64,Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,),Tuple{Bool}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,),Tuple{Bool}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,),Tuple{Symbol}},typeof(plot),Array{Tuple{Int64,Real},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,),Tuple{Symbol}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,),Tuple{Symbol}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :lab, :ms),Tuple{Tuple{Array{Symbol,2},Int64},Array{String,2},Int64}},typeof(plot),Array{Array{T,1} where T,1},Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :label, :legendtitle),Tuple{Tuple{Int64,Array{Symbol,2}},Array{String,2},String}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :leg, :fill),Tuple{Int64,Bool,Tuple{Int64,Symbol}}},typeof(plot),Function,Function,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :marker, :bg, :fg, :xlim, :ylim, :leg),Tuple{Tuple{Int64,Symbol,Symbol},Tuple{Shape,Int64,RGBA{Float64}},Symbol,Symbol,Tuple{Int64,Int64},Tuple{Int64,Int64},Bool}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line_z, :linewidth, :legend),Tuple{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Int64,Bool}},typeof(plot),Array{Float64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:m, :lab, :bg, :xlim, :ylim, :seriestype),Tuple{Tuple{Int64,Symbol},Array{String,2},Symbol,Tuple{Int64,Int64},Tuple{Int64,Int64},Symbol}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:marker,),Tuple{Bool}},typeof(plot),Array{Union{Missing, Int64},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:marker_z, :color, :legend, :seriestype),Tuple{typeof(+),Symbol,Bool,Symbol}},typeof(plot),Array{Float64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:nbins, :seriestype),Tuple{Int64,Symbol}},typeof(plot),Array{Float64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:nbins, :show_empty_bins, :normed, :aspect_ratio, :seriestype),Tuple{Tuple{Int64,Int64},Bool,Bool,Int64,Symbol}},typeof(plot),Array{Complex{Float64},1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:proj, :m),Tuple{Symbol,Int64}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:projection, :seriestype),Tuple{Symbol,Symbol}},typeof(plot),Array{Int64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:quiver, :seriestype),Tuple{Tuple{Array{Float64,1},Array{Float64,1},Array{Float64,1}},Symbol}},typeof(plot),Array{Float64,1},Array{Float64,1},Vararg{Array{Float64,1},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:reg, :fill),Tuple{Bool,Tuple{Int64,Symbol}}},typeof(plot),Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,),Tuple{Int64}},typeof(plot),UnitRange{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,),Tuple{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}}},typeof(plot),UnitRange{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,),Tuple{Tuple{LinRange{Float64},LinRange{Float64}}}},typeof(plot),UnitRange{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,),Tuple{typeof(sqrt)}},typeof(plot),UnitRange{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype, :markershape, :markersize, :color),Tuple{Array{Symbol,2},Array{Symbol,1},Int64,Array{Symbol,1}}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,),Tuple{Symbol}},typeof(plot),Array{DateTime,1},UnitRange{Int64},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,),Tuple{Symbol}},typeof(plot),Array{OHLC,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:st, :xlabel, :ylabel, :zlabel),Tuple{Symbol,String,String,String}},typeof(plot),Array{Float64,1},Array{Float64,1},Vararg{Array{Float64,1},N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :l, :seriestype),Tuple{String,Float64,Symbol}},typeof(plot),Array{String,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,),Tuple{Array{String,2}}},typeof(plot),Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,),Tuple{Array{String,2}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,),Tuple{String}},typeof(plot),Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,),Tuple{String}},typeof(plot),Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:w,),Tuple{Int64}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:xaxis, :background_color, :leg),Tuple{Tuple{String,Tuple{Int64,Int64},StepRange{Int64,Int64},Symbol},RGB{Float64},Bool}},typeof(plot),Array{Float64,2}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:yflip, :aspect_ratio),Tuple{Bool,Symbol}},typeof(plot),Array{Float64,1},Array{Int64,1},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:zcolor, :m, :leg, :cbar, :w),Tuple{StepRange{Int64,Int64},Tuple{Int64,Float64,Symbol,Stroke},Bool,Bool,Int64}},typeof(plot),Array{Float64,1},Array{Float64,1},Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(portfoliocomposition)),Any,typeof(portfoliocomposition),Any,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(scatter!)),Any,typeof(scatter!),Any,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(scatter!)),Any,typeof(scatter!),Any})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(test_examples)),NamedTuple{(:skip, :disp),Tuple{Array{Int64,1},Bool}},typeof(test_examples),Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(test_examples)),NamedTuple{(:skip,),Tuple{Array{Int64,1}}},typeof(test_examples),Symbol})
|
||||
Base.precompile(Tuple{Type{GridLayout},Int64,Vararg{Int64,N} where N})
|
||||
Base.precompile(Tuple{Type{Shape},Array{Tuple{Float64,Float64},1}})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},AbstractArray{OHLC,1}})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Array{Complex{Float64},1}})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},PortfolioComposition})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:barbins}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:barhist}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:bar}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:histogram2d}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:hline}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:pie}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:quiver}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:spy}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:sticks}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:xerror}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plot{GRBackend},DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plot{PlotlyBackend},DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{GRBackend},Dict{Symbol,Any},Array{Dict{Symbol,Any},1}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{PlotlyBackend},Dict{Symbol,Any},Array{Dict{Symbol,Any},1}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plot{GRBackend},DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{GRBackend},Array{Dict{Symbol,Any},1},Dict{Symbol,Any}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{PlotlyBackend},Array{Dict{Symbol,Any},1},Dict{Symbol,Any}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},DefaultsDict,Symbol,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},Dict{Symbol,Any},Symbol,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{PlotlyBackend},DefaultsDict,Symbol,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{PlotlyBackend},Dict{Symbol,Any},Symbol,Any})
|
||||
Base.precompile(Tuple{typeof(_bin_centers),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Array{Int64,1},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Array{Nothing,1},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Array{PlotUtils.ContinuousColorGradient,1},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Array{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},1},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Array{Symbol,1},String})
|
||||
Base.precompile(Tuple{typeof(_cycle),Array{Float64,1},Array{Int64,1}})
|
||||
Base.precompile(Tuple{typeof(_cycle),Array{Float64,1},StepRange{Int64,Int64}})
|
||||
Base.precompile(Tuple{typeof(_cycle),Array{Float64,1},UnitRange{Int64}})
|
||||
Base.precompile(Tuple{typeof(_cycle),Base.OneTo{Int64},Array{Int64,1}})
|
||||
Base.precompile(Tuple{typeof(_cycle),StepRange{Int64,Int64},Array{Int64,1}})
|
||||
Base.precompile(Tuple{typeof(_do_plot_show),Plot{GRBackend},Bool})
|
||||
Base.precompile(Tuple{typeof(_do_plot_show),Plot{PlotlyBackend},Bool})
|
||||
Base.precompile(Tuple{typeof(_heatmap_edges),Array{Float64,1},Bool})
|
||||
Base.precompile(Tuple{typeof(_plot!),Plot,Any,Any})
|
||||
Base.precompile(Tuple{typeof(_preprocess_barlike),DefaultsDict,Base.OneTo{Int64},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(_preprocess_binlike),DefaultsDict,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(_replace_markershape),Array{Symbol,1}})
|
||||
Base.precompile(Tuple{typeof(_update_min_padding!),GridLayout})
|
||||
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{GRBackend},Subplot{GRBackend},Dict{Symbol,Any},Int64,Bool})
|
||||
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{PlotlyBackend},Subplot{PlotlyBackend},Dict{Symbol,Any},Int64,Bool})
|
||||
Base.precompile(Tuple{typeof(backend),PlotlyBackend})
|
||||
Base.precompile(Tuple{typeof(bbox),Float64,Float64,Float64,Float64})
|
||||
Base.precompile(Tuple{typeof(bbox),Length{:mm,Float64},Length{:mm,Float64},Length{:mm,Float64},Length{:mm,Float64}})
|
||||
Base.precompile(Tuple{typeof(build_layout),GridLayout,Int64})
|
||||
Base.precompile(Tuple{typeof(contour),Any,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{typeof(convert_to_polar),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1},Tuple{Int64,Float64}})
|
||||
Base.precompile(Tuple{typeof(create_grid),Expr})
|
||||
Base.precompile(Tuple{typeof(error_coords),Array{Float64,1},Array{Float64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(error_zipit),Tuple{Array{Float64,1},Array{Float64,1},Array{Float64,1}}})
|
||||
Base.precompile(Tuple{typeof(fakedata),Int64,Vararg{Int64,N} where N})
|
||||
Base.precompile(Tuple{typeof(font),String,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{typeof(get_clims),Subplot{GRBackend},Series,Function})
|
||||
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Array{Float64,1},Array{String,1}}})
|
||||
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Array{Int64,1},Array{String,1}}})
|
||||
Base.precompile(Tuple{typeof(get_series_color),Array{Symbol,1},Subplot{GRBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_series_color),Array{Symbol,1},Subplot{PlotlyBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_series_color),PlotUtils.ContinuousColorGradient,Subplot{GRBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_xy),Array{OHLC,1}})
|
||||
Base.precompile(Tuple{typeof(get_xy),OHLC{Float64},Int64,Float64})
|
||||
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor),NTuple{9,Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor),Tuple{Int64,Float64,Float64,Float64,Int64,Float64,Float64,Float64,Float64}},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(gr_display),Subplot{GRBackend},Length{:mm,Float64},Length{:mm,Float64},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_colorbar),GRColorbar,Subplot{GRBackend},Tuple{Float64,Float64},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_contour),Series,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,2},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_grid),Subplot{GRBackend},Axis,Segments{Tuple{Float64,Float64}}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_heatmap),Series,Array{Float64,1},Array{Float64,1},Array{Float64,2},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_heatmap),Series,Base.OneTo{Int64},Base.OneTo{Int64},Array{Float64,2},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Array{Int64,1},Array{Float64,1},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Base.OneTo{Int64},Array{Float64,1},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_markers),Series,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Array{Float64,1},Array{Float64,1},Int64,Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Array{Int64,1},Array{Int64,1},Nothing,Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},Array{Float64,1},Int64,Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},Array{Float64,1},Nothing,Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},UnitRange{Int64},Tuple{Array{Float64,1},Array{Float64,1}},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,StepRange{Int64,Int64},Array{Float64,1},Int64,Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Array{Float64,1},Array{Float64,1},Array{Float64,1},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Array{Float64,1},Array{Float64,1},Array{Float64,2},Tuple{Float64,Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Array{Float64,1},Array{Any,1}},Int64})
|
||||
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Array{Float64,1},Array{String,1}},Int64})
|
||||
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Array{Int64,1},Array{String,1}},Int64})
|
||||
Base.precompile(Tuple{typeof(gr_label_ticks),Subplot{GRBackend},Symbol,Tuple{Array{Float64,1},Array{String,1}}})
|
||||
Base.precompile(Tuple{typeof(gr_label_ticks_3d),Subplot{GRBackend},Symbol,Tuple{Array{Float64,1},Array{String,1}}})
|
||||
Base.precompile(Tuple{typeof(gr_polaraxes),Int64,Float64,Subplot{GRBackend}})
|
||||
Base.precompile(Tuple{typeof(gr_polyline),Array{Float64,1},Array{Float64,1},Function})
|
||||
Base.precompile(Tuple{typeof(gr_set_gradient),PlotUtils.ContinuousColorGradient})
|
||||
Base.precompile(Tuple{typeof(heatmap_edges),Array{Float64,1},Symbol})
|
||||
Base.precompile(Tuple{typeof(heatmap_edges),Base.OneTo{Int64},Symbol})
|
||||
Base.precompile(Tuple{typeof(heatmap_edges),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Symbol})
|
||||
Base.precompile(Tuple{typeof(heatmap_edges),UnitRange{Int64},Symbol})
|
||||
Base.precompile(Tuple{typeof(ignorenan_minimum),Array{Int64,1}})
|
||||
Base.precompile(Tuple{typeof(iter_segments),Array{Float64,1},Array{Float64,1},UnitRange{Int64}})
|
||||
Base.precompile(Tuple{typeof(iter_segments),Array{Float64,1},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(iter_segments),Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(iter_segments),Base.OneTo{Int64},Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(layout_args),Int64})
|
||||
Base.precompile(Tuple{typeof(make_fillrange_side),UnitRange{Int64},LinRange{Float64}})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Subplot{GRBackend},Axis,StepRange{Int64,Int64}})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Subplot{GRBackend},Axis,UnitRange{Int64}})
|
||||
Base.precompile(Tuple{typeof(plot!),Any})
|
||||
Base.precompile(Tuple{typeof(plot),Any,Any})
|
||||
Base.precompile(Tuple{typeof(plot),Any})
|
||||
Base.precompile(Tuple{typeof(processFontArg!),Dict{Symbol,Any},Symbol,String})
|
||||
Base.precompile(Tuple{typeof(processGridArg!),DefaultsDict,Bool,Symbol})
|
||||
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol,Any},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol,Any},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol,Any},Array{Symbol,2}})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol,Any},Int64})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol,Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol,Any},Array{Symbol,2}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol,Any},RGBA{Float64}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol,Any},Shape})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol,Any},Stroke})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol,Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,PlotText})
|
||||
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,PlotText})
|
||||
Base.precompile(Tuple{typeof(process_axis_arg!),Dict{Symbol,Any},StepRange{Int64,Int64},Symbol})
|
||||
Base.precompile(Tuple{typeof(process_axis_arg!),Dict{Symbol,Any},String,Symbol})
|
||||
Base.precompile(Tuple{typeof(process_axis_arg!),Dict{Symbol,Any},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(process_axis_arg!),Dict{Symbol,Any},Tuple{Int64,Int64},Symbol})
|
||||
Base.precompile(Tuple{typeof(push!),Plot{GRBackend},Float64,Array{Float64,1}})
|
||||
Base.precompile(Tuple{typeof(quiver_using_arrows),DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(quiver_using_hack),DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(reset_axis_defaults_byletter!)})
|
||||
Base.precompile(Tuple{typeof(setindex!),Plot{GRBackend},RGBA{Float64},Symbol})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Array{Length{:mm,Float64},2},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Array{PlotUtils.ContinuousColorGradient,2},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Array{RGBA{Float64},2},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Array{String,2},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Array{Symbol,2},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}},Int64})
|
||||
Base.precompile(Tuple{typeof(spy),Any})
|
||||
Base.precompile(Tuple{typeof(straightline_data),Tuple{Float64,Float64},Tuple{Float64,Float64},Array{Float64,1},Array{Float64,1},Int64})
|
||||
Base.precompile(Tuple{typeof(stroke),Int64,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{typeof(text),String,Int64,Symbol,Vararg{Symbol,N} where N})
|
||||
Base.precompile(Tuple{typeof(text),String,Symbol,Int64,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{typeof(text),String,Symbol})
|
||||
Base.precompile(Tuple{typeof(title!),AbstractString})
|
||||
Base.precompile(Tuple{typeof(unzip),Array{GeometryBasics.Point{2,Float64},1}})
|
||||
Base.precompile(Tuple{typeof(vline!),Any})
|
||||
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any,N} where N})
|
||||
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{typeof(yaxis!),Any,Any})
|
||||
let fbody = try __lookup_kwbody__(which(gr_polyline, (Array{Float64,1},Array{Float64,1},typeof(GR.fillarea),))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Symbol,Symbol,typeof(gr_polyline),Array{Float64,1},Array{Float64,1},typeof(GR.fillarea),))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot!, ())) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot!),))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot!, (Any,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot!),Any,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot!, (Any,Vararg{Any,N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot!),Any,Vararg{Any,N} where N,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot, (Any,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot),Any,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot, (Any,Vararg{Any,N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot),Any,Vararg{Any,N} where N,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot, (Plot,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot),Plot,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot, (Plot,Plot,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot),Plot,Plot,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot, (Plot,Plot,Vararg{Plot,N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot),Plot,Plot,Vararg{Plot,N} where N,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(text, (String,Int64,Vararg{Any,N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},typeof(text),String,Int64,Vararg{Any,N} where N,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(text, (String,Symbol,Vararg{Any,N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},typeof(text),String,Symbol,Vararg{Any,N} where N,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(title!, (AbstractString,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(title!),AbstractString,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(vline!, (Any,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(vline!),Any,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(yaxis!, (Any,Vararg{Any,N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(yaxis!),Any,Vararg{Any,N} where N,))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
using Plots
|
||||
|
||||
Plots.test_examples(:gr, skip = Plots._backend_skips[:gr])
|
||||
Plots.test_examples(:plotly, skip = Plots._backend_skips[:plotly], disp = false)
|
||||
@@ -0,0 +1,8 @@
|
||||
using CompileBot
|
||||
|
||||
snoop_bench(
|
||||
BotConfig(
|
||||
"Plots",
|
||||
),
|
||||
joinpath(@__DIR__, "precompile_script.jl"),
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
using CompileBot
|
||||
|
||||
snoop_bot(
|
||||
BotConfig(
|
||||
"Plots",
|
||||
),
|
||||
joinpath(@__DIR__, "precompile_script.jl"),
|
||||
)
|
||||
@@ -1,132 +0,0 @@
|
||||
|
||||
module PlotExamples
|
||||
|
||||
using Plots
|
||||
using Colors
|
||||
|
||||
const DOCDIR = Pkg.dir("Plots") * "/docs"
|
||||
const IMGDIR = Pkg.dir("Plots") * "/img"
|
||||
|
||||
doc"""
|
||||
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
|
||||
"""
|
||||
type PlotExample
|
||||
header::String
|
||||
desc::String
|
||||
exprs::Vector{Expr}
|
||||
end
|
||||
|
||||
|
||||
# the examples we'll run for each
|
||||
const examples = PlotExample[
|
||||
PlotExample("Lines",
|
||||
"A simple line plot of the 3 columns.",
|
||||
[:(plot(rand(100,3)))]),
|
||||
PlotExample("Functions",
|
||||
"Plot multiple functions.",
|
||||
[:(plot(0:0.01:4π, [sin,cos]))]),
|
||||
PlotExample("",
|
||||
"You can also call it with plot(f, xmin, xmax).",
|
||||
[:(plot([sin,cos], 0, 4π))]),
|
||||
PlotExample("",
|
||||
"Or make a parametric plot with plot(fx, fy, umin, umax).",
|
||||
[:(plot(sin, x->sin(2x), 0, 2π))]),
|
||||
PlotExample("Global",
|
||||
"Change the guides/background without a separate call.",
|
||||
[:(plot(rand(10); title="TITLE", xlabel="XLABEL", ylabel="YLABEL", background_color = RGB(0.5,0.5,0.5)))]),
|
||||
PlotExample("Two-axis",
|
||||
"Use the `axis` or `axiss` arguments.\n\nNote: This is only supported with Qwt right now",
|
||||
[:(plot(Vector[randn(100), randn(100)*100]; axiss = [:left,:right]))]),
|
||||
PlotExample("Vectors w/ pluralized args",
|
||||
"Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).",
|
||||
[:(plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8, colors=[:red,:blue]))]),
|
||||
PlotExample("Build plot in pieces",
|
||||
"Start with a base plot...",
|
||||
[:(plot(rand(100)/3; reg=true, fillto=0))]),
|
||||
PlotExample("",
|
||||
"and add to it later.",
|
||||
[:(scatter!(rand(100); markersize=6, color=:blue))]),
|
||||
PlotExample("Heatmaps",
|
||||
"",
|
||||
[:(heatmap(randn(10000),randn(10000); nbins=200))]),
|
||||
PlotExample("Lots of line types",
|
||||
"Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar) \nNote: some may not work with all backends",
|
||||
[:(plot(rand(20,4); linetypes=[:line, :step, :sticks, :dots], labels=["line","step","sticks","dots"]))]),
|
||||
PlotExample("Bar",
|
||||
"x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)",
|
||||
[:(bar(randn(1000)))]),
|
||||
PlotExample("Histogram",
|
||||
"note: fillto isn't supported on all backends",
|
||||
[:(histogram(randn(1000); nbins=50, fillto=20))]),
|
||||
PlotExample("Subplots",
|
||||
"""
|
||||
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
|
||||
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
|
||||
number of columns `nc`), or you can set the layout directly with `layout`.
|
||||
|
||||
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
|
||||
""",
|
||||
[:(subplot(randn(100,5); layout=[1,1,3], linetypes=[:line,:hist,:dots,:step,:bar], nbins=10, legend=false))]),
|
||||
PlotExample("Adding to subplots",
|
||||
"Note here the automatic grid layout, as well as the order in which new series are added to the plots.",
|
||||
[:(subplot(randn(100,5); n=4))]),
|
||||
PlotExample("",
|
||||
"",
|
||||
[:(subplot!(randn(100,3)))]),
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
function generate_markdown(pkgname::Symbol)
|
||||
|
||||
# set up the plotter, and don't show the plots by default
|
||||
plotter!(pkgname)
|
||||
plotDefault!(:show, false)
|
||||
|
||||
# mkdir if necessary
|
||||
try
|
||||
mkdir("$IMGDIR/$pkgname")
|
||||
end
|
||||
|
||||
# open the markdown file
|
||||
md = open("$DOCDIR/$(pkgname)_examples.md", "w")
|
||||
|
||||
for (i,example) in enumerate(examples)
|
||||
|
||||
try
|
||||
|
||||
# run the code
|
||||
map(eval, example.exprs)
|
||||
|
||||
# save the png
|
||||
imgname = "$(pkgname)_example_$i.png"
|
||||
savepng("$IMGDIR/$pkgname/$imgname")
|
||||
|
||||
# write out the header, description, code block, and image link
|
||||
write(md, "### $(example.header)\n\n")
|
||||
write(md, "$(example.desc)\n\n")
|
||||
write(md, "```julia\n$(join(map(string, example.exprs), "\n"))\n```\n\n")
|
||||
write(md, "\n\n")
|
||||
|
||||
catch ex
|
||||
# TODO: put error info into markdown?
|
||||
warn("Example $pkgname:$i failed with: $ex")
|
||||
end
|
||||
|
||||
#
|
||||
end
|
||||
|
||||
close(md)
|
||||
|
||||
end
|
||||
|
||||
# run it!
|
||||
# note: generate separately so it's easy to comment out
|
||||
generate_markdown(:qwt)
|
||||
generate_markdown(:gadfly)
|
||||
generate_markdown(:unicodeplots)
|
||||
|
||||
|
||||
end # module
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
### Lines
|
||||
|
||||
A simple line plot of the 3 columns.
|
||||
|
||||
```julia
|
||||
plot(rand(100,3))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Functions
|
||||
|
||||
Plot multiple functions.
|
||||
|
||||
```julia
|
||||
plot(0:0.01:4π,[sin,cos])
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
You can also call it with plot(f, xmin, xmax).
|
||||
|
||||
```julia
|
||||
plot([sin,cos],0,4π)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
Or make a parametric plot with plot(fx, fy, umin, umax).
|
||||
|
||||
```julia
|
||||
plot(sin,(x->begin # /Users/tom/.julia/v0.4/Plots/docs/example_generation.jl, line 33:
|
||||
sin(2x)
|
||||
end),0,2π)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Global
|
||||
|
||||
Change the guides/background without a separate call.
|
||||
|
||||
```julia
|
||||
plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.5,0.5,0.5))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Two-axis
|
||||
|
||||
Use the `axis` or `axiss` arguments.
|
||||
|
||||
Note: This is only supported with Qwt right now
|
||||
|
||||
```julia
|
||||
plot(Vector[randn(100),randn(100) * 100]; axiss=[:left,:right])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Vectors w/ pluralized args
|
||||
|
||||
Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).
|
||||
|
||||
```julia
|
||||
plot(Vector[rand(10),rand(20)]; marker=:ellipse,markersize=8,colors=[:red,:blue])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Build plot in pieces
|
||||
|
||||
Start with a base plot...
|
||||
|
||||
```julia
|
||||
plot(rand(100) / 3; reg=true,fillto=0)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
and add to it later.
|
||||
|
||||
```julia
|
||||
scatter!(rand(100); markersize=6,color=:blue)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Heatmaps
|
||||
|
||||
|
||||
|
||||
```julia
|
||||
heatmap(randn(10000),randn(10000); nbins=200)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Lots of line types
|
||||
|
||||
Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar)
|
||||
Note: some may not work with all backends
|
||||
|
||||
```julia
|
||||
plot(rand(20,4); linetypes=[:line,:step,:sticks,:dots],labels=["line","step","sticks","dots"])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Bar
|
||||
|
||||
x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)
|
||||
|
||||
```julia
|
||||
bar(randn(1000))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Histogram
|
||||
|
||||
note: fillto isn't supported on all backends
|
||||
|
||||
```julia
|
||||
histogram(randn(1000); nbins=50,fillto=20)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Subplots
|
||||
|
||||
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
|
||||
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
|
||||
number of columns `nc`), or you can set the layout directly with `layout`.
|
||||
|
||||
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
|
||||
|
||||
|
||||
```julia
|
||||
subplot(randn(100,5); layout=[1,1,3],linetypes=[:line,:hist,:dots,:step,:bar],nbins=10,legend=false)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Adding to subplots
|
||||
|
||||
Note here the automatic grid layout, as well as the order in which new series are added to the plots.
|
||||
|
||||
```julia
|
||||
subplot(randn(100,5); n=4)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
|
||||
|
||||
```julia
|
||||
subplot!(randn(100,3))
|
||||
```
|
||||
|
||||

|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
### Lines
|
||||
|
||||
A simple line plot of the 3 columns.
|
||||
|
||||
```julia
|
||||
plot(rand(100,3))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Functions
|
||||
|
||||
Plot multiple functions.
|
||||
|
||||
```julia
|
||||
plot(0:0.01:4π,[sin,cos])
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
You can also call it with plot(f, xmin, xmax).
|
||||
|
||||
```julia
|
||||
plot([sin,cos],0,4π)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
Or make a parametric plot with plot(fx, fy, umin, umax).
|
||||
|
||||
```julia
|
||||
plot(sin,(x->begin # /Users/tom/.julia/v0.4/Plots/docs/example_generation.jl, line 33:
|
||||
sin(2x)
|
||||
end),0,2π)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Global
|
||||
|
||||
Change the guides/background without a separate call.
|
||||
|
||||
```julia
|
||||
plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.5,0.5,0.5))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Two-axis
|
||||
|
||||
Use the `axis` or `axiss` arguments.
|
||||
|
||||
Note: This is only supported with Qwt right now
|
||||
|
||||
```julia
|
||||
plot(Vector[randn(100),randn(100) * 100]; axiss=[:left,:right])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Vectors w/ pluralized args
|
||||
|
||||
Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).
|
||||
|
||||
```julia
|
||||
plot(Vector[rand(10),rand(20)]; marker=:ellipse,markersize=8,colors=[:red,:blue])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Build plot in pieces
|
||||
|
||||
Start with a base plot...
|
||||
|
||||
```julia
|
||||
plot(rand(100) / 3; reg=true,fillto=0)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
and add to it later.
|
||||
|
||||
```julia
|
||||
scatter!(rand(100); markersize=6,color=:blue)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Heatmaps
|
||||
|
||||
|
||||
|
||||
```julia
|
||||
heatmap(randn(10000),randn(10000); nbins=200)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Lots of line types
|
||||
|
||||
Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar)
|
||||
Note: some may not work with all backends
|
||||
|
||||
```julia
|
||||
plot(rand(20,4); linetypes=[:line,:step,:sticks,:dots],labels=["line","step","sticks","dots"])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Bar
|
||||
|
||||
x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)
|
||||
|
||||
```julia
|
||||
bar(randn(1000))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Histogram
|
||||
|
||||
note: fillto isn't supported on all backends
|
||||
|
||||
```julia
|
||||
histogram(randn(1000); nbins=50,fillto=20)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Subplots
|
||||
|
||||
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
|
||||
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
|
||||
number of columns `nc`), or you can set the layout directly with `layout`.
|
||||
|
||||
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
|
||||
|
||||
|
||||
```julia
|
||||
subplot(randn(100,5); layout=[1,1,3],linetypes=[:line,:hist,:dots,:step,:bar],nbins=10,legend=false)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Adding to subplots
|
||||
|
||||
Note here the automatic grid layout, as well as the order in which new series are added to the plots.
|
||||
|
||||
```julia
|
||||
subplot(randn(100,5); n=4)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
|
||||
|
||||
```julia
|
||||
subplot!(randn(100,3))
|
||||
```
|
||||
|
||||

|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
### Lines
|
||||
|
||||
A simple line plot of the 3 columns.
|
||||
|
||||
```julia
|
||||
plot(rand(100,3))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Functions
|
||||
|
||||
Plot multiple functions.
|
||||
|
||||
```julia
|
||||
plot(0:0.01:4π,[sin,cos])
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
You can also call it with plot(f, xmin, xmax).
|
||||
|
||||
```julia
|
||||
plot([sin,cos],0,4π)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
Or make a parametric plot with plot(fx, fy, umin, umax).
|
||||
|
||||
```julia
|
||||
plot(sin,(x->begin # /Users/tom/.julia/v0.4/Plots/docs/example_generation.jl, line 33:
|
||||
sin(2x)
|
||||
end),0,2π)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Global
|
||||
|
||||
Change the guides/background without a separate call.
|
||||
|
||||
```julia
|
||||
plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.5,0.5,0.5))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Two-axis
|
||||
|
||||
Use the `axis` or `axiss` arguments.
|
||||
|
||||
Note: This is only supported with Qwt right now
|
||||
|
||||
```julia
|
||||
plot(Vector[randn(100),randn(100) * 100]; axiss=[:left,:right])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Vectors w/ pluralized args
|
||||
|
||||
Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).
|
||||
|
||||
```julia
|
||||
plot(Vector[rand(10),rand(20)]; marker=:ellipse,markersize=8,colors=[:red,:blue])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Build plot in pieces
|
||||
|
||||
Start with a base plot...
|
||||
|
||||
```julia
|
||||
plot(rand(100) / 3; reg=true,fillto=0)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
and add to it later.
|
||||
|
||||
```julia
|
||||
scatter!(rand(100); markersize=6,color=:blue)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Lots of line types
|
||||
|
||||
Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar)
|
||||
Note: some may not work with all backends
|
||||
|
||||
```julia
|
||||
plot(rand(20,4); linetypes=[:line,:step,:sticks,:dots],labels=["line","step","sticks","dots"])
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Bar
|
||||
|
||||
x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)
|
||||
|
||||
```julia
|
||||
bar(randn(1000))
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Histogram
|
||||
|
||||
note: fillto isn't supported on all backends
|
||||
|
||||
```julia
|
||||
histogram(randn(1000); nbins=50,fillto=20)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Subplots
|
||||
|
||||
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
|
||||
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
|
||||
number of columns `nc`), or you can set the layout directly with `layout`.
|
||||
|
||||
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
|
||||
|
||||
|
||||
```julia
|
||||
subplot(randn(100,5); layout=[1,1,3],linetypes=[:line,:hist,:dots,:step,:bar],nbins=10,legend=false)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Adding to subplots
|
||||
|
||||
Note here the automatic grid layout, as well as the order in which new series are added to the plots.
|
||||
|
||||
```julia
|
||||
subplot(randn(100,5); n=4)
|
||||
```
|
||||
|
||||

|
||||
|
||||
###
|
||||
|
||||
|
||||
|
||||
```julia
|
||||
subplot!(randn(100,3))
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 55 KiB |
@@ -1,74 +1,254 @@
|
||||
__precompile__()
|
||||
|
||||
module Plots
|
||||
|
||||
using Colors
|
||||
if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel"))
|
||||
@eval Base.Experimental.@optlevel 1
|
||||
end
|
||||
|
||||
const _current_plots_version = VersionNumber(split(first(filter(line -> occursin("version", line), readlines(normpath(@__DIR__, "..", "Project.toml")))), "\"")[2])
|
||||
|
||||
using Reexport
|
||||
|
||||
import GeometryBasics
|
||||
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
|
||||
using SparseArrays
|
||||
|
||||
using FFMPEG
|
||||
|
||||
@reexport using RecipesBase
|
||||
import RecipesBase: plot, plot!, animate, is_explicit
|
||||
using Base.Meta
|
||||
@reexport using PlotUtils
|
||||
@reexport using PlotThemes
|
||||
import Showoff
|
||||
import StatsBase
|
||||
import JSON
|
||||
|
||||
using Requires
|
||||
|
||||
export
|
||||
plotter,
|
||||
plot,
|
||||
subplot,
|
||||
grid,
|
||||
bbox,
|
||||
plotarea,
|
||||
@layout,
|
||||
KW,
|
||||
|
||||
plotter!,
|
||||
plot!,
|
||||
subplot!,
|
||||
wrap,
|
||||
theme,
|
||||
|
||||
currentPlot,
|
||||
plotDefault,
|
||||
scatter,
|
||||
bar,
|
||||
histogram,
|
||||
heatmap,
|
||||
plot,
|
||||
plot!,
|
||||
attr!,
|
||||
|
||||
currentPlot!,
|
||||
plotDefault!,
|
||||
scatter!,
|
||||
bar!,
|
||||
histogram!,
|
||||
heatmap!,
|
||||
current,
|
||||
default,
|
||||
with,
|
||||
twinx,
|
||||
|
||||
savepng,
|
||||
pie,
|
||||
pie!,
|
||||
plot3d,
|
||||
plot3d!,
|
||||
|
||||
backends,
|
||||
qwt!,
|
||||
gadfly!,
|
||||
unicodeplots!
|
||||
title!,
|
||||
xlabel!,
|
||||
ylabel!,
|
||||
xlims!,
|
||||
ylims!,
|
||||
zlims!,
|
||||
xticks!,
|
||||
yticks!,
|
||||
annotate!,
|
||||
xflip!,
|
||||
yflip!,
|
||||
xaxis!,
|
||||
yaxis!,
|
||||
xgrid!,
|
||||
ygrid!,
|
||||
|
||||
# ---------------------------------------------------------
|
||||
xlims,
|
||||
ylims,
|
||||
zlims,
|
||||
|
||||
savefig,
|
||||
png,
|
||||
gui,
|
||||
inline,
|
||||
closeall,
|
||||
|
||||
const IMG_DIR = Pkg.dir("Plots") * "/img/"
|
||||
backend,
|
||||
backends,
|
||||
backend_name,
|
||||
backend_object,
|
||||
aliases,
|
||||
|
||||
Shape,
|
||||
text,
|
||||
font,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
arrow,
|
||||
Segments,
|
||||
Formatted,
|
||||
|
||||
Animation,
|
||||
frame,
|
||||
gif,
|
||||
mov,
|
||||
mp4,
|
||||
webm,
|
||||
animate,
|
||||
@animate,
|
||||
@gif,
|
||||
|
||||
test_examples,
|
||||
iter_segments,
|
||||
coords,
|
||||
|
||||
translate,
|
||||
translate!,
|
||||
rotate,
|
||||
rotate!,
|
||||
center,
|
||||
BezierCurve,
|
||||
|
||||
plotattr,
|
||||
scalefontsize,
|
||||
scalefontsizes,
|
||||
resetfontsizes
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
|
||||
ignorenan_minimum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.minimum(x)
|
||||
ignorenan_minimum(x) = Base.minimum(x)
|
||||
ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
|
||||
ignorenan_maximum(x) = Base.maximum(x)
|
||||
ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
|
||||
ignorenan_mean(x) = Statistics.mean(x)
|
||||
ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
|
||||
ignorenan_extrema(x) = Base.extrema(x)
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# to cater for block matrices, Base.transpose is recursive.
|
||||
# This makes it impossible to create row vectors of String and Symbol with the transpose operator.
|
||||
# This solves this issue, internally in Plots at least.
|
||||
|
||||
|
||||
# commented out on the insistence of the METADATA maintainers
|
||||
|
||||
#Base.transpose(x::Symbol) = x
|
||||
#Base.transpose(x::String) = 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
|
||||
|
||||
# allow pixels and percentages
|
||||
const px = AbsoluteLength(0.254)
|
||||
const pct = Length{:pct, Float64}(1.0)
|
||||
|
||||
Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
|
||||
Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
|
||||
Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
|
||||
Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)
|
||||
|
||||
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h
|
||||
end
|
||||
|
||||
using .PlotMeasures
|
||||
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
|
||||
# ---------------------------------------------------------
|
||||
|
||||
import RecipesPipeline
|
||||
import RecipesPipeline: SliceIt,
|
||||
DefaultsDict,
|
||||
Formatted,
|
||||
AbstractSurface,
|
||||
Surface,
|
||||
Volume,
|
||||
is3d,
|
||||
is_surface,
|
||||
needs_3d_axes,
|
||||
group_as_matrix, # for StatsPlots
|
||||
reset_kw!,
|
||||
pop_kw!,
|
||||
scale_func,
|
||||
inverse_scale_func,
|
||||
unzip,
|
||||
dateformatter,
|
||||
datetimeformatter,
|
||||
timeformatter
|
||||
|
||||
# Use fixed version of Plotly instead of the latest one for stable dependency
|
||||
# Ref: https://github.com/JuliaPlots/Plots.jl/pull/2779
|
||||
const _plotly_min_js_filename = "plotly-1.57.1.min.js"
|
||||
|
||||
include("types.jl")
|
||||
include("utils.jl")
|
||||
include("plotter.jl")
|
||||
include("axes.jl")
|
||||
include("args.jl")
|
||||
include("components.jl")
|
||||
include("themes.jl")
|
||||
include("plot.jl")
|
||||
include("subplot.jl")
|
||||
include("pipeline.jl")
|
||||
include("layouts.jl")
|
||||
include("subplots.jl")
|
||||
include("recipes.jl")
|
||||
include("animation.jl")
|
||||
include("examples.jl")
|
||||
include("arg_desc.jl")
|
||||
include("plotattr.jl")
|
||||
include("backends.jl")
|
||||
include("output.jl")
|
||||
include("ijulia.jl")
|
||||
include("fileio.jl")
|
||||
include("init.jl")
|
||||
|
||||
include("backends/plotly.jl")
|
||||
include("backends/gr.jl")
|
||||
include("backends/web.jl")
|
||||
|
||||
include("shorthands.jl")
|
||||
|
||||
let PlotOrSubplot = Union{Plot, Subplot}
|
||||
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
|
||||
global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
|
||||
global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
|
||||
global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
|
||||
global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
|
||||
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
|
||||
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
|
||||
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
|
||||
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...)
|
||||
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...)
|
||||
global xticks!(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
|
||||
global yticks!(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
|
||||
global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
|
||||
global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
|
||||
global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
|
||||
global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
|
||||
global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
|
||||
global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
|
||||
global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
scatter(args...; kw...) = plot(args...; kw..., linetype = :none, marker = :hexagon)
|
||||
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :none, marker = :hexagon)
|
||||
bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
|
||||
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
|
||||
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
|
||||
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
|
||||
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
|
||||
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
savepng(args...; kw...) = savepng(currentPlot(), args...; kw...)
|
||||
savepng(plt::PlottingObject, args...; kw...) = savepng(plt.plotter, plt, args...; kw...)
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
include("precompile_includer.jl")
|
||||
|
||||
end # module
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
"Represents an animation object"
|
||||
struct Animation
|
||||
dir::String
|
||||
frames::Vector{String}
|
||||
end
|
||||
|
||||
function Animation()
|
||||
tmpdir = convert(String, mktempdir())
|
||||
Animation(tmpdir, String[])
|
||||
end
|
||||
|
||||
"""
|
||||
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))
|
||||
push!(anim.frames, filename)
|
||||
end
|
||||
|
||||
giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
|
||||
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
|
||||
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
|
||||
webmfn() = (isijulia() ? "tmp.webm" : tempname()*".webm")
|
||||
|
||||
mutable struct FrameIterator
|
||||
itr
|
||||
every::Int
|
||||
kw
|
||||
end
|
||||
FrameIterator(itr; every=1, kw...) = FrameIterator(itr, every, kw)
|
||||
|
||||
"""
|
||||
Animate from an iterator which returns the plot args each iteration.
|
||||
"""
|
||||
function animate(fitr::FrameIterator, fn = giffn(); kw...)
|
||||
anim = Animation()
|
||||
for (i, plotargs) in enumerate(fitr.itr)
|
||||
if mod1(i, fitr.every) == 1
|
||||
plot(wraptuple(plotargs)...; fitr.kw...)
|
||||
frame(anim)
|
||||
end
|
||||
end
|
||||
gif(anim, fn; kw...)
|
||||
end
|
||||
|
||||
# most things will implement this
|
||||
function animate(obj, fn = giffn(); every=1, fps=20, loop=0, kw...)
|
||||
animate(FrameIterator(obj, every, kw), fn; fps=fps, loop=loop)
|
||||
end
|
||||
|
||||
# -----------------------------------------------
|
||||
|
||||
"Wraps the location of an animated gif so that it can be displayed"
|
||||
struct AnimatedGif
|
||||
filename::String
|
||||
end
|
||||
|
||||
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
|
||||
|
||||
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim, fn; kw...)
|
||||
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim, fn, false; kw...)
|
||||
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim, fn, false; kw...)
|
||||
webm(anim::Animation, fn = webmfn(); kw...) = buildanimation(anim, fn, false; kw...)
|
||||
|
||||
ffmpeg_framerate(fps) = "$fps"
|
||||
ffmpeg_framerate(fps::Rational) = "$(fps.num)/$(fps.den)"
|
||||
|
||||
function buildanimation(anim::Animation, fn::AbstractString,
|
||||
is_animated_gif::Bool=true;
|
||||
fps::Real = 20, loop::Integer = 0,
|
||||
variable_palette::Bool=false,
|
||||
verbose=false,
|
||||
show_msg::Bool=true)
|
||||
if length(anim.frames) == 0
|
||||
throw(ArgumentError("Cannot build empty animations"))
|
||||
end
|
||||
|
||||
fn = abspath(expanduser(fn))
|
||||
animdir = anim.dir
|
||||
framerate = ffmpeg_framerate(fps)
|
||||
verbose_level = (verbose isa Int ? verbose :
|
||||
verbose ? 32 # "info"
|
||||
: 16) # "error"
|
||||
|
||||
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"
|
||||
ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`)
|
||||
else
|
||||
# generate a colorpalette first so ffmpeg does not have to guess it
|
||||
ffmpeg_exe(`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
|
||||
# then apply the palette to get better results
|
||||
ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`)
|
||||
end
|
||||
else
|
||||
ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -vf format=yuv420p -loop $loop -y $fn`)
|
||||
end
|
||||
|
||||
show_msg && @info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# write out html to view the gif
|
||||
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
ext = file_extension(agif.filename)
|
||||
if ext == "gif"
|
||||
html = "<img src=\"data:image/gif;base64," * base64encode(read(agif.filename)) * "\" />"
|
||||
elseif ext in ("mov", "mp4","webm")
|
||||
mimetype = ext == "mov" ? "video/quicktime" : "video/$ext"
|
||||
html = "<video controls><source src=\"data:$mimetype;base64," *
|
||||
base64encode(read(agif.filename)) *
|
||||
"\" type = \"$mimetype\"></video>"
|
||||
else
|
||||
error("Cannot show animation with extension $ext: $agif")
|
||||
end
|
||||
|
||||
write(io, html)
|
||||
return nothing
|
||||
end
|
||||
|
||||
|
||||
# Only gifs can be shown via image/gif
|
||||
Base.showable(::MIME"image/gif", agif::AnimatedGif) = file_extension(agif.filename) == "gif"
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/gif", agif::AnimatedGif)
|
||||
open(fio-> write(io, fio), agif.filename)
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------
|
||||
|
||||
function _animate(forloop::Expr, args...; callgif = false)
|
||||
if forloop.head != :for
|
||||
error("@animate macro expects a for-block. got: $(forloop.head)")
|
||||
end
|
||||
|
||||
# add the call to frame to the end of each iteration
|
||||
animsym = gensym("anim")
|
||||
countersym = gensym("counter")
|
||||
freqassert = :()
|
||||
block = forloop.args[2]
|
||||
|
||||
# create filter
|
||||
n = length(args)
|
||||
filterexpr = if n == 0
|
||||
# no filter... every iteration gets a frame
|
||||
true
|
||||
|
||||
elseif args[1] == :every
|
||||
# filter every `freq` frames (starting with the first frame)
|
||||
@assert n == 2
|
||||
freq = args[2]
|
||||
freqassert = :(@assert isa($freq, Integer) && $freq > 0)
|
||||
:(mod1($countersym, $freq) == 1)
|
||||
|
||||
elseif args[1] == :when
|
||||
# filter on custom expression
|
||||
@assert n == 2
|
||||
args[2]
|
||||
|
||||
else
|
||||
error("Unsupported animate filter: $args")
|
||||
end
|
||||
|
||||
push!(block.args, :(if $filterexpr; Plots.frame($animsym); end))
|
||||
push!(block.args, :(global $countersym += 1))
|
||||
|
||||
# add a final call to `gif(anim)`?
|
||||
retval = callgif ? :(Plots.gif($animsym)) : animsym
|
||||
|
||||
# full expression:
|
||||
esc(quote
|
||||
$freqassert # if filtering, check frequency is an Integer > 0
|
||||
$animsym = Plots.Animation() # init animation object
|
||||
global $countersym = 1 # init iteration counter
|
||||
$forloop # for loop, saving a frame after each iteration
|
||||
$retval # return the animation object, or the gif
|
||||
end)
|
||||
end
|
||||
|
||||
"""
|
||||
Builds an `Animation` using one frame per loop iteration, then create an animated GIF.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
p = plot(1)
|
||||
@gif for x=0:0.1:5
|
||||
push!(p, 1, sin(x))
|
||||
end
|
||||
```
|
||||
"""
|
||||
macro gif(forloop::Expr, args...)
|
||||
_animate(forloop, args...; callgif = true)
|
||||
end
|
||||
|
||||
"""
|
||||
Collect one frame per for-block iteration and return an `Animation` object.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
p = plot(1)
|
||||
anim = @animate for x=0:0.1:5
|
||||
push!(p, 1, sin(x))
|
||||
end
|
||||
gif(anim)
|
||||
```
|
||||
"""
|
||||
macro animate(forloop::Expr, args...)
|
||||
_animate(forloop, args...)
|
||||
end
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
const _arg_desc = KW(
|
||||
|
||||
# series args
|
||||
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
|
||||
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
|
||||
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
|
||||
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
|
||||
:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)",
|
||||
:linewidth => "Number. Width of the line (in pixels)",
|
||||
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
|
||||
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
|
||||
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
|
||||
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
|
||||
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
|
||||
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
|
||||
:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.",
|
||||
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
|
||||
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers.",
|
||||
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
|
||||
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
|
||||
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
|
||||
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`",
|
||||
:smooth => "Bool. Add a regression line?",
|
||||
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
|
||||
:x => "Various. Input data. First Dimension",
|
||||
:y => "Various. Input data. Second Dimension",
|
||||
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
|
||||
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
|
||||
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
|
||||
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
|
||||
:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.",
|
||||
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
|
||||
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
|
||||
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
|
||||
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
|
||||
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
|
||||
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
|
||||
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
|
||||
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
|
||||
: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 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.",
|
||||
:show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default).",
|
||||
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
|
||||
:contour_labels => "Bool. Show labels at the contour lines?",
|
||||
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
|
||||
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
|
||||
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
|
||||
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
|
||||
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
|
||||
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
|
||||
|
||||
# plot args
|
||||
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
|
||||
:background_color => "Color Type. Base color for all backgrounds.",
|
||||
:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)",
|
||||
:foreground_color => "Color Type. Base color for all foregrounds.",
|
||||
:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot",
|
||||
:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)",
|
||||
:window_title => "String. Title of the standalone gui-window.",
|
||||
:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`",
|
||||
:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.",
|
||||
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
|
||||
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
|
||||
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
|
||||
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.",
|
||||
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
|
||||
:dpi => "Number. Dots Per Inch of output figures",
|
||||
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
|
||||
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
|
||||
:extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`",
|
||||
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
|
||||
:warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes",
|
||||
|
||||
# subplot args
|
||||
:title => "String. Subplot title.",
|
||||
:titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
|
||||
: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).",
|
||||
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
|
||||
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
|
||||
:foreground_color_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 (x,y) tuple or Symbol (legend position). Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend)",
|
||||
: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",
|
||||
:legendtitle => "String. Legend title.",
|
||||
:legendtitlefontfamily => "String or Symbol. Font family of the legend title.",
|
||||
:legendtitlefontsize => "Integer. Font pointsize the legend title.",
|
||||
:legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center",
|
||||
:legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center",
|
||||
:legendtitlefontrotation => "Real. Font rotation of the legend title",
|
||||
:legendtitlefontcolor => "Color Type. Font color of the legend title",
|
||||
: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`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.",
|
||||
:legendfont => "Font. Font of legend items.",
|
||||
:legendtitlefont => "Font. Font of the legend title.",
|
||||
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
|
||||
:projection => "Symbol or String. '3d' or 'polar'",
|
||||
:aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.",
|
||||
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
|
||||
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
|
||||
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
|
||||
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
|
||||
: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).",
|
||||
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
|
||||
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
|
||||
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
|
||||
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
|
||||
:rotation => "Number. Degrees rotation of tick labels.",
|
||||
:flip => "Bool. Should we flip (reverse) the axis?",
|
||||
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
|
||||
:tickfontfamily => "String or Symbol. Font family of tick labels.",
|
||||
:tickfontsize => "Integer. Font pointsize of tick labels.",
|
||||
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
|
||||
: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? `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)",
|
||||
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
|
||||
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
|
||||
:minorticks => "Integer. Intervals to divide the gap between major ticks into",
|
||||
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
|
||||
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
|
||||
:minorgridlinewidth => "Number. Width of the minor 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`",
|
||||
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
|
||||
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
|
||||
)
|
||||
@@ -0,0 +1,856 @@
|
||||
|
||||
|
||||
# xaxis(args...; kw...) = Axis(:x, args...; kw...)
|
||||
# yaxis(args...; kw...) = Axis(:y, args...; kw...)
|
||||
# zaxis(args...; kw...) = Axis(:z, args...; kw...)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
explicit = KW(
|
||||
:letter => letter,
|
||||
:extrema => Extrema(),
|
||||
:discrete_map => Dict(), # map discrete values to discrete indices
|
||||
:continuous_values => zeros(0),
|
||||
:discrete_values => [],
|
||||
:use_minor => false,
|
||||
:show => true, # show or hide the axis? (useful for linked subplots)
|
||||
)
|
||||
|
||||
attr = DefaultsDict(explicit, _axis_defaults_byletter[letter])
|
||||
|
||||
# update the defaults
|
||||
attr!(Axis([sp], attr), args...; kw...)
|
||||
end
|
||||
|
||||
function get_axis(sp::Subplot, letter::Symbol)
|
||||
axissym = Symbol(letter, :axis)
|
||||
if haskey(sp.attr, axissym)
|
||||
sp.attr[axissym]
|
||||
else
|
||||
sp.attr[axissym] = Axis(sp, letter)
|
||||
end::Axis
|
||||
end
|
||||
|
||||
function process_axis_arg!(plotattributes::AKW, arg, letter = "")
|
||||
T = typeof(arg)
|
||||
arg = get(_scaleAliases, arg, arg)
|
||||
if typeof(arg) <: Font
|
||||
plotattributes[Symbol(letter,:tickfont)] = arg
|
||||
plotattributes[Symbol(letter,:guidefont)] = arg
|
||||
|
||||
elseif arg in _allScales
|
||||
plotattributes[Symbol(letter,:scale)] = arg
|
||||
|
||||
elseif arg in (:flip, :invert, :inverted)
|
||||
plotattributes[Symbol(letter,:flip)] = true
|
||||
|
||||
elseif T <: AbstractString
|
||||
plotattributes[Symbol(letter,:guide)] = arg
|
||||
|
||||
# xlims/ylims
|
||||
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
|
||||
sym = typeof(arg[1]) <: Number ? :lims : :ticks
|
||||
plotattributes[Symbol(letter,sym)] = arg
|
||||
|
||||
# xticks/yticks
|
||||
elseif T <: AVec
|
||||
plotattributes[Symbol(letter,:ticks)] = arg
|
||||
|
||||
elseif arg === nothing
|
||||
plotattributes[Symbol(letter,:ticks)] = []
|
||||
|
||||
elseif T <: Bool || arg in _allShowaxisArgs
|
||||
plotattributes[Symbol(letter,:showaxis)] = showaxis(arg, letter)
|
||||
|
||||
elseif typeof(arg) <: Number
|
||||
plotattributes[Symbol(letter,:rotation)] = arg
|
||||
|
||||
elseif typeof(arg) <: Function
|
||||
plotattributes[Symbol(letter,:formatter)] = arg
|
||||
|
||||
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis))
|
||||
@warn("Skipped $(letter)axis arg $arg")
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# update an Axis object with magic args and keywords
|
||||
function attr!(axis::Axis, args...; kw...)
|
||||
# first process args
|
||||
plotattributes = axis.plotattributes
|
||||
for arg in args
|
||||
process_axis_arg!(plotattributes, arg)
|
||||
end
|
||||
|
||||
# then preprocess keyword arguments
|
||||
RecipesPipeline.preprocess_attributes!(KW(kw))
|
||||
|
||||
# then override for any keywords... only those keywords that already exists in plotattributes
|
||||
for (k,v) in kw
|
||||
if haskey(plotattributes, k)
|
||||
if k == :discrete_values
|
||||
# add these discrete values to the axis
|
||||
for vi in v
|
||||
discrete_value!(axis, vi)
|
||||
end
|
||||
#could perhaps use TimeType here, as Date and DateTime are both subtypes of TimeType
|
||||
# or could perhaps check if dateformatter or datetimeformatter is in use
|
||||
elseif k == :lims && isa(v, Tuple{Date,Date})
|
||||
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
|
||||
elseif k == :lims && isa(v, Tuple{DateTime,DateTime})
|
||||
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
|
||||
else
|
||||
plotattributes[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# replace scale aliases
|
||||
if haskey(_scaleAliases, plotattributes[:scale])
|
||||
plotattributes[:scale] = _scaleAliases[plotattributes[:scale]]
|
||||
end
|
||||
|
||||
axis
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
Base.show(io::IO, axis::Axis) = dumpdict(io, axis.plotattributes, "Axis", true)
|
||||
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.plotattributes, k)
|
||||
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v, ks...)
|
||||
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k)
|
||||
ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
|
||||
|
||||
const _label_func = Dict{Symbol,Function}(
|
||||
:log10 => x -> "10^$x",
|
||||
:log2 => x -> "2^$x",
|
||||
:ln => x -> "e^$x",
|
||||
)
|
||||
labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string)
|
||||
|
||||
const _label_func_tex = Dict{Symbol,Function}(
|
||||
:log10 => x -> "10^{$x}",
|
||||
:log2 => x -> "2^{$x}",
|
||||
:ln => x -> "e^{$x}",
|
||||
)
|
||||
labelfunc_tex(scale::Symbol) = get(_label_func_tex, scale, convert_sci_unicode)
|
||||
|
||||
|
||||
function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
|
||||
amin, amax = axis_limits(sp, axis[:letter])
|
||||
|
||||
# scale the limits
|
||||
scale = axis[:scale]
|
||||
sf = RecipesPipeline.scale_func(scale)
|
||||
|
||||
# If the axis input was a Date or DateTime use a special logic to find
|
||||
# "round" Date(Time)s as ticks
|
||||
# This bypasses the rest of optimal_ticks_and_labels, because
|
||||
# optimize_datetime_ticks returns ticks AND labels: the label format (Date
|
||||
# or DateTime) is chosen based on the time span between amin and amax
|
||||
# rather than on the input format
|
||||
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
|
||||
if ticks === nothing && scale == :identity
|
||||
if axis[:formatter] == RecipesPipeline.dateformatter
|
||||
# optimize_datetime_ticks returns ticks and labels(!) based on
|
||||
# integers/floats corresponding to the DateTime type. Thus, the axes
|
||||
# limits, which resulted from converting the Date type to integers,
|
||||
# are converted to 'DateTime integers' (actually floats) before
|
||||
# being passed to optimize_datetime_ticks.
|
||||
# (convert(Int, convert(DateTime, convert(Date, i))) == 87600000*i)
|
||||
ticks, labels = optimize_datetime_ticks(864e5 * amin, 864e5 * amax;
|
||||
k_min = 2, k_max = 4)
|
||||
# Now the ticks are converted back to floats corresponding to Dates.
|
||||
return ticks / 864e5, labels
|
||||
elseif axis[:formatter] == RecipesPipeline.datetimeformatter
|
||||
return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4)
|
||||
end
|
||||
end
|
||||
|
||||
# get a list of well-laid-out ticks
|
||||
if ticks === nothing
|
||||
scaled_ticks = optimize_ticks(
|
||||
sf(amin),
|
||||
sf(amax);
|
||||
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(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax))
|
||||
else
|
||||
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
|
||||
end
|
||||
unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks)
|
||||
|
||||
labels = if any(isfinite, unscaled_ticks)
|
||||
formatter = axis[:formatter]
|
||||
if formatter in (:auto, :plain, :scientific, :engineering)
|
||||
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, formatter))
|
||||
elseif formatter == :latex
|
||||
map(x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"), Showoff.showoff(unscaled_ticks, :auto))
|
||||
else
|
||||
# there was an override for the formatter... use that on the unscaled ticks
|
||||
map(formatter, unscaled_ticks)
|
||||
# if the formatter left us with numbers, still apply the default formatter
|
||||
# However it leave us with the problem of unicode number decoding by the backend
|
||||
# if eltype(unscaled_ticks) <: Number
|
||||
# Showoff.showoff(unscaled_ticks, :auto)
|
||||
# end
|
||||
end
|
||||
else
|
||||
# no finite ticks to show...
|
||||
String[]
|
||||
end
|
||||
|
||||
# @show unscaled_ticks labels
|
||||
# labels = Showoff.showoff(unscaled_ticks, scale == :log10 ? :scientific : :auto)
|
||||
unscaled_ticks, labels
|
||||
end
|
||||
|
||||
# return (continuous_values, discrete_values) for the ticks on this axis
|
||||
function get_ticks(sp::Subplot, axis::Axis; update = true)
|
||||
if update || !haskey(axis.plotattributes, :optimized_ticks)
|
||||
ticks = _transform_ticks(axis[:ticks])
|
||||
if ticks in (:none, nothing, false)
|
||||
axis.plotattributes[:optimized_ticks] = nothing
|
||||
else
|
||||
# treat :native ticks as :auto
|
||||
ticks = ticks == :native ? :auto : ticks
|
||||
|
||||
dvals = axis[:discrete_values]
|
||||
cv, dv = if typeof(ticks) <: Symbol
|
||||
if !isempty(dvals)
|
||||
# discrete ticks...
|
||||
n = length(dvals)
|
||||
rng = if ticks == :auto && n > 15
|
||||
Δ = ceil(Int, n / 10)
|
||||
Δ:Δ:n
|
||||
else # if ticks == :all
|
||||
1:n
|
||||
end
|
||||
axis[:continuous_values][rng], dvals[rng]
|
||||
elseif ispolar(axis.sps[1]) && axis[:letter] == :x
|
||||
#force theta axis to be full circle
|
||||
(collect(0:pi/4:7pi/4), string.(0:45:315))
|
||||
else
|
||||
# compute optimal ticks and labels
|
||||
optimal_ticks_and_labels(sp, axis)
|
||||
end
|
||||
elseif typeof(ticks) <: Union{AVec, Int}
|
||||
if !isempty(dvals) && typeof(ticks) <: Int
|
||||
rng = Int[round(Int,i) for i in range(1, stop=length(dvals), length=ticks)]
|
||||
axis[:continuous_values][rng], dvals[rng]
|
||||
else
|
||||
# override ticks, but get the labels
|
||||
optimal_ticks_and_labels(sp, axis, ticks)
|
||||
end
|
||||
elseif typeof(ticks) <: NTuple{2, Any}
|
||||
# assuming we're passed (ticks, labels)
|
||||
ticks
|
||||
else
|
||||
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
|
||||
end
|
||||
axis.plotattributes[:optimized_ticks] = (cv, dv)
|
||||
end
|
||||
end
|
||||
axis.plotattributes[:optimized_ticks]
|
||||
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])
|
||||
|
||||
function get_minor_ticks(sp, axis, ticks)
|
||||
axis[:minorticks] in (:none, nothing, false) && !axis[:minorgrid] && return nothing
|
||||
ticks = ticks[1]
|
||||
length(ticks) < 2 && return nothing
|
||||
|
||||
amin, amax = axis_limits(sp, axis[:letter])
|
||||
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
|
||||
if length(ticks) > 2
|
||||
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
|
||||
elseif axis[:scale] in (:none, :identity)
|
||||
ratio = 1
|
||||
else
|
||||
return nothing
|
||||
end
|
||||
first_step = ticks[2] - ticks[1]
|
||||
last_step = ticks[end] - ticks[end-1]
|
||||
ticks = [ticks[1] - first_step/ratio; ticks; ticks[end] + last_step*ratio]
|
||||
|
||||
#Default to 5 intervals between major ticks
|
||||
n = typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : 5
|
||||
minorticks = typeof(ticks[1])[]
|
||||
for (i,hi) in enumerate(ticks[2:end])
|
||||
lo = ticks[i]
|
||||
if isfinite(lo) && isfinite(hi) && hi > lo
|
||||
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
|
||||
end
|
||||
end
|
||||
minorticks[amin .<= minorticks .<= amax]
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
function reset_extrema!(sp::Subplot)
|
||||
for asym in (:x,:y,:z)
|
||||
sp[Symbol(asym,:axis)][:extrema] = Extrema()
|
||||
end
|
||||
for series in sp.series_list
|
||||
expand_extrema!(sp, series.plotattributes)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function expand_extrema!(ex::Extrema, v::Number)
|
||||
ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin
|
||||
ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax
|
||||
ex
|
||||
end
|
||||
|
||||
function expand_extrema!(axis::Axis, v::Number)
|
||||
expand_extrema!(axis[:extrema], v)
|
||||
end
|
||||
|
||||
# these shouldn't impact the extrema
|
||||
expand_extrema!(axis::Axis, ::Nothing) = axis[:extrema]
|
||||
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
|
||||
|
||||
|
||||
function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
|
||||
ex = axis[:extrema]
|
||||
ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin
|
||||
ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax
|
||||
ex
|
||||
end
|
||||
function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
|
||||
ex = axis[:extrema]
|
||||
for vi in v
|
||||
expand_extrema!(ex, vi)
|
||||
end
|
||||
ex
|
||||
end
|
||||
|
||||
|
||||
function expand_extrema!(sp::Subplot, plotattributes::AKW)
|
||||
vert = isvertical(plotattributes)
|
||||
|
||||
# first expand for the data
|
||||
for letter in (:x, :y, :z)
|
||||
data = plotattributes[if vert
|
||||
letter
|
||||
else
|
||||
letter == :x ? :y : letter == :y ? :x : :z
|
||||
end]
|
||||
if letter != :z && plotattributes[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
|
||||
data = [NaN]
|
||||
end
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
|
||||
if isa(data, Volume)
|
||||
expand_extrema!(sp[:xaxis], data.x_extents)
|
||||
expand_extrema!(sp[:yaxis], data.y_extents)
|
||||
expand_extrema!(sp[:zaxis], data.z_extents)
|
||||
elseif eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf))
|
||||
if !(eltype(data) <: Number)
|
||||
# huh... must have been a mis-typed surface? lets swap it out
|
||||
data = plotattributes[letter] = Surface(Matrix{Float64}(data.surf))
|
||||
end
|
||||
expand_extrema!(axis, data)
|
||||
elseif data !== nothing
|
||||
# TODO: need more here... gotta track the discrete reference value
|
||||
# as well as any coord offset (think of boxplot shape coords... they all
|
||||
# correspond to the same x-value)
|
||||
plotattributes[letter], plotattributes[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
|
||||
expand_extrema!(axis, plotattributes[letter])
|
||||
end
|
||||
end
|
||||
|
||||
# # expand for fillrange/bar_width
|
||||
# fillaxis, baraxis = sp.attr[:yaxis], sp.attr[:xaxis]
|
||||
# if isvertical(plotattributes)
|
||||
# fillaxis, baraxis = baraxis, fillaxis
|
||||
# end
|
||||
|
||||
# expand for fillrange
|
||||
fr = plotattributes[:fillrange]
|
||||
if fr === nothing && plotattributes[:seriestype] == :bar
|
||||
fr = 0.0
|
||||
end
|
||||
if fr !== nothing && !RecipesPipeline.is3d(plotattributes)
|
||||
axis = sp.attr[vert ? :yaxis : :xaxis]
|
||||
if typeof(fr) <: Tuple
|
||||
for fri in fr
|
||||
expand_extrema!(axis, fri)
|
||||
end
|
||||
else
|
||||
expand_extrema!(axis, fr)
|
||||
end
|
||||
end
|
||||
|
||||
# expand for bar_width
|
||||
if plotattributes[:seriestype] == :bar
|
||||
dsym = vert ? :x : :y
|
||||
data = plotattributes[dsym]
|
||||
|
||||
bw = plotattributes[:bar_width]
|
||||
if bw === nothing
|
||||
bw = plotattributes[: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 plotattributes[:seriestype] == :heatmap
|
||||
for letter in (:x, :y)
|
||||
data = plotattributes[letter]
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
scale = get(plotattributes, Symbol(letter, "scale"), :identity)
|
||||
expand_extrema!(axis, heatmap_edges(data, scale))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax)
|
||||
expand_extrema!(sp[:xaxis], (xmin, xmax))
|
||||
expand_extrema!(sp[:yaxis], (ymin, ymax))
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# push the limits out slightly
|
||||
function widen(lmin, lmax, scale = :identity)
|
||||
f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale)
|
||||
span = f(lmax) - f(lmin)
|
||||
# eps = NaNMath.max(1e-16, min(1e-2span, 1e-10))
|
||||
eps = NaNMath.max(1e-16, 0.03span)
|
||||
invf(f(lmin)-eps), invf(f(lmax)+eps)
|
||||
end
|
||||
|
||||
# figure out if widening is a good idea.
|
||||
const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d)
|
||||
|
||||
function default_should_widen(axis::Axis)
|
||||
should_widen = false
|
||||
if !(is_2tuple(axis[:lims]) || axis[:lims] == :round)
|
||||
for sp in axis.sps
|
||||
for series in series_list(sp)
|
||||
if series.plotattributes[:seriestype] in _widen_seriestypes
|
||||
should_widen = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
should_widen
|
||||
end
|
||||
|
||||
function round_limits(amin,amax)
|
||||
scale = 10^(1-round(log10(amax - amin)))
|
||||
amin = floor(amin*scale)/scale
|
||||
amax = ceil(amax*scale)/scale
|
||||
amin, amax
|
||||
end
|
||||
|
||||
# using the axis extrema and limit overrides, return the min/max value for this axis
|
||||
function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(letter, :axis)]), consider_aspect = true)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
ex = axis[:extrema]
|
||||
amin, amax = ex.emin, ex.emax
|
||||
lims = axis[:lims]
|
||||
has_user_lims = (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
|
||||
if has_user_lims
|
||||
lmin, lmax = lims
|
||||
if lmin != :auto && isfinite(lmin)
|
||||
amin = lmin
|
||||
end
|
||||
if lmax != :auto && isfinite(lmax)
|
||||
amax = lmax
|
||||
end
|
||||
end
|
||||
if amax <= amin && isfinite(amin)
|
||||
amax = amin + 1.0
|
||||
end
|
||||
if !isfinite(amin) && !isfinite(amax)
|
||||
amin, amax = 0.0, 1.0
|
||||
end
|
||||
amin, amax = if ispolar(axis.sps[1])
|
||||
if axis[:letter] == :x
|
||||
amin, amax = 0, 2pi
|
||||
elseif lims == :auto
|
||||
#widen max radius so ticks dont overlap with theta axis
|
||||
0, amax + 0.1 * abs(amax - amin)
|
||||
else
|
||||
amin, amax
|
||||
end
|
||||
elseif should_widen && axis[:widen]
|
||||
widen(amin, amax, axis[:scale])
|
||||
elseif lims == :round
|
||||
round_limits(amin,amax)
|
||||
else
|
||||
amin, amax
|
||||
end
|
||||
|
||||
if !has_user_lims && consider_aspect && letter in (:x, :y) && !(sp[:aspect_ratio] in (:none, :auto) || RecipesPipeline.is3d(:sp))
|
||||
aspect_ratio = isa(sp[:aspect_ratio], Number) ? sp[:aspect_ratio] : 1
|
||||
plot_ratio = height(plotarea(sp)) / width(plotarea(sp))
|
||||
dist = amax - amin
|
||||
|
||||
if letter == :x
|
||||
yamin, yamax = axis_limits(sp, :y, default_should_widen(sp[:yaxis]), false)
|
||||
ydist = yamax - yamin
|
||||
axis_ratio = aspect_ratio * ydist / dist
|
||||
factor = axis_ratio / plot_ratio
|
||||
else
|
||||
xamin, xamax = axis_limits(sp, :x, default_should_widen(sp[:xaxis]), false)
|
||||
xdist = xamax - xamin
|
||||
axis_ratio = aspect_ratio * dist / xdist
|
||||
factor = plot_ratio / axis_ratio
|
||||
end
|
||||
|
||||
if factor > 1
|
||||
center = (amin + amax) / 2
|
||||
amin = center + factor * (amin - center)
|
||||
amax = center + factor * (amax - center)
|
||||
end
|
||||
end
|
||||
|
||||
return amin, amax
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# these methods track the discrete (categorical) values which correspond to axis continuous values (cv)
|
||||
# whenever we have discrete values, we automatically set the ticks to match.
|
||||
# we return (continuous_value, discrete_index)
|
||||
function discrete_value!(axis::Axis, dv)
|
||||
cv_idx = get(axis[:discrete_map], dv, -1)
|
||||
# @show axis[:discrete_map], axis[:discrete_values], dv
|
||||
if cv_idx == -1
|
||||
ex = axis[:extrema]
|
||||
cv = NaNMath.max(0.5, ex.emax + 1.0)
|
||||
expand_extrema!(axis, cv)
|
||||
push!(axis[:discrete_values], dv)
|
||||
push!(axis[:continuous_values], cv)
|
||||
cv_idx = length(axis[:discrete_values])
|
||||
axis[:discrete_map][dv] = cv_idx
|
||||
cv, cv_idx
|
||||
else
|
||||
cv = axis[:continuous_values][cv_idx]
|
||||
cv, cv_idx
|
||||
end
|
||||
end
|
||||
|
||||
# continuous value... just pass back with axis negative index
|
||||
function discrete_value!(axis::Axis, cv::Number)
|
||||
cv, -1
|
||||
end
|
||||
|
||||
# add the discrete value for each item. return the continuous values and the indices
|
||||
function discrete_value!(axis::Axis, v::AVec)
|
||||
n = eachindex(v)
|
||||
cvec = zeros(axes(v))
|
||||
discrete_indices = similar(Array{Int}, axes(v))
|
||||
for i in n
|
||||
cvec[i], discrete_indices[i] = discrete_value!(axis, v[i])
|
||||
end
|
||||
cvec, discrete_indices
|
||||
end
|
||||
|
||||
# add the discrete value for each item. return the continuous values and the indices
|
||||
function discrete_value!(axis::Axis, v::AMat)
|
||||
n,m = axes(v)
|
||||
cmat = zeros(axes(v))
|
||||
discrete_indices = similar(Array{Int}, axes(v))
|
||||
for i in n, j in m
|
||||
cmat[i,j], discrete_indices[i,j] = discrete_value!(axis, v[i,j])
|
||||
end
|
||||
cmat, discrete_indices
|
||||
end
|
||||
|
||||
function discrete_value!(axis::Axis, v::Surface)
|
||||
map(Surface, discrete_value!(axis, v.surf))
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# compute the line segments which should be drawn for this axis
|
||||
function axis_drawing_info(sp, letter)
|
||||
# find out which axis we are dealing with
|
||||
asym = Symbol(letter, :axis)
|
||||
isy = letter === :y
|
||||
oletter = isy ? :x : :y
|
||||
oasym = Symbol(oletter, :axis)
|
||||
|
||||
# get axis objects, ticks and minor ticks
|
||||
ax, oax = sp[asym], sp[oasym]
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
oamin, oamax = axis_limits(sp, oletter)
|
||||
ticks = get_ticks(sp, ax, update = false)
|
||||
minor_ticks = get_minor_ticks(sp, ax, ticks)
|
||||
|
||||
# initialize the segments
|
||||
segments = Segments(2)
|
||||
tick_segments = Segments(2)
|
||||
grid_segments = Segments(2)
|
||||
minorgrid_segments = Segments(2)
|
||||
border_segments = Segments(2)
|
||||
|
||||
if sp[:framestyle] != :none
|
||||
oa1, oa2 = if sp[:framestyle] in (:origin, :zerolines)
|
||||
0.0, 0.0
|
||||
else
|
||||
xor(ax[:mirror], oax[:flip]) ? (oamax, oamin) : (oamin, oamax)
|
||||
end
|
||||
if ax[:showaxis]
|
||||
if sp[:framestyle] != :grid
|
||||
push!(segments, reverse_if((amin, oa1), isy), reverse_if((amax, oa1), isy))
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1
|
||||
i = findfirst(==(0), ticks[1])
|
||||
if i !== nothing
|
||||
deleteat!(ticks[1], i)
|
||||
deleteat!(ticks[2], i)
|
||||
end
|
||||
end
|
||||
end
|
||||
if sp[:framestyle] in (:semi, :box) # top spine
|
||||
push!(
|
||||
border_segments,
|
||||
reverse_if((amin, oa2), isy),
|
||||
reverse_if((amax, oa2), isy),
|
||||
)
|
||||
end
|
||||
end
|
||||
if !(ax[:ticks] in (:none, nothing, false))
|
||||
f = RecipesPipeline.scale_func(oax[:scale])
|
||||
invf = RecipesPipeline.inverse_scale_func(oax[:scale])
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
t = invf(f(0) + 0.012 * (f(oamax) - f(oamin)))
|
||||
(-t, t)
|
||||
else
|
||||
ticks_in = ax[:tick_direction] == :out ? -1 : 1
|
||||
t = invf(f(oa1) + 0.012 * (f(oa2) - f(oa1)) * ticks_in)
|
||||
(oa1, t)
|
||||
end
|
||||
|
||||
for tick in ticks[1]
|
||||
if ax[:showaxis]
|
||||
push!(
|
||||
tick_segments,
|
||||
reverse_if((tick, tick_start), isy),
|
||||
reverse_if((tick, tick_stop), isy),
|
||||
)
|
||||
end
|
||||
if ax[:grid]
|
||||
push!(
|
||||
grid_segments,
|
||||
reverse_if((tick, oamin), isy),
|
||||
reverse_if((tick, oamax), isy),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
if !(ax[:minorticks] in (:none, nothing, false)) || ax[:minorgrid]
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
t = invf(f(0) + 0.006 * (f(oamax) - f(oamin)))
|
||||
(-t, t)
|
||||
else
|
||||
t = invf(f(oa1) + 0.006 * (f(oa2) - f(oa1)) * ticks_in)
|
||||
(oa1, t)
|
||||
end
|
||||
for tick in minor_ticks
|
||||
if ax[:showaxis]
|
||||
push!(
|
||||
tick_segments,
|
||||
reverse_if((tick, tick_start), isy),
|
||||
reverse_if((tick, tick_stop), isy),
|
||||
)
|
||||
end
|
||||
if ax[:minorgrid]
|
||||
push!(
|
||||
minorgrid_segments,
|
||||
reverse_if((tick, oamin), isy),
|
||||
reverse_if((tick, oamax), isy),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return (
|
||||
ticks = ticks,
|
||||
segments = segments,
|
||||
tick_segments = tick_segments,
|
||||
grid_segments = grid_segments,
|
||||
minorgrid_segments = minorgrid_segments,
|
||||
border_segments = border_segments
|
||||
)
|
||||
end
|
||||
|
||||
function sort_3d_axes(a, b, c, letter)
|
||||
if letter === :x
|
||||
a, b, c
|
||||
elseif letter === :y
|
||||
b, a, c
|
||||
else
|
||||
c, b, a
|
||||
end
|
||||
end
|
||||
|
||||
function axis_drawing_info_3d(sp, letter)
|
||||
near_letter = letter in (:x, :z) ? :y : :x
|
||||
far_letter = letter in (:x, :y) ? :z : :x
|
||||
|
||||
ax = sp[Symbol(letter, :axis)]
|
||||
nax = sp[Symbol(near_letter, :axis)]
|
||||
fax = sp[Symbol(far_letter, :axis)]
|
||||
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
namin, namax = axis_limits(sp, near_letter)
|
||||
famin, famax = axis_limits(sp, far_letter)
|
||||
|
||||
ticks = get_ticks(sp, ax, update = false)
|
||||
minor_ticks = get_minor_ticks(sp, ax, ticks)
|
||||
|
||||
# initialize the segments
|
||||
segments = Segments(3)
|
||||
tick_segments = Segments(3)
|
||||
grid_segments = Segments(3)
|
||||
minorgrid_segments = Segments(3)
|
||||
border_segments = Segments(3)
|
||||
|
||||
|
||||
if sp[:framestyle] != :none# && letter === :x
|
||||
na0, na1 = if sp[:framestyle] in (:origin, :zerolines)
|
||||
0, 0
|
||||
else
|
||||
# reverse_if((namin, namax), xor(ax[:mirror], nax[:flip]))
|
||||
reverse_if(reverse_if((namin, namax), letter === :y), xor(ax[:mirror], nax[:flip]))
|
||||
end
|
||||
fa0, fa1 = if sp[:framestyle] in (:origin, :zerolines)
|
||||
0, 0
|
||||
else
|
||||
reverse_if((famin, famax), xor(ax[:mirror], fax[:flip]))
|
||||
end
|
||||
if ax[:showaxis]
|
||||
if sp[:framestyle] != :grid
|
||||
push!(
|
||||
segments,
|
||||
sort_3d_axes(amin, na0, fa0, letter),
|
||||
sort_3d_axes(amax, na0, fa0, letter),
|
||||
)
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1
|
||||
i0 = findfirst(==(0), ticks[1])
|
||||
if ind !== nothing
|
||||
deleteat!(ticks[1], i0)
|
||||
deleteat!(ticks[2], i0)
|
||||
end
|
||||
end
|
||||
end
|
||||
if sp[:framestyle] in (:semi, :box)
|
||||
push!(
|
||||
border_segments,
|
||||
sort_3d_axes(amin, na1, fa1, letter),
|
||||
sort_3d_axes(amax, na1, fa1, letter),
|
||||
)
|
||||
end
|
||||
end
|
||||
# TODO this can be simplified, we do almost the same thing twice for grid and minorgrid
|
||||
if !(ax[:ticks] in (:none, nothing, false))
|
||||
f = RecipesPipeline.scale_func(nax[:scale])
|
||||
invf = RecipesPipeline.inverse_scale_func(nax[:scale])
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
t = invf(f(0) + 0.012 * (f(namax) - f(namin)))
|
||||
(-t, t)
|
||||
else
|
||||
ticks_in = ax[:tick_direction] == :out ? -1 : 1
|
||||
t = invf(f(na0) + 0.012 * (f(na1) - f(na0)) * ticks_in)
|
||||
(na0, t)
|
||||
end
|
||||
|
||||
ga0, ga1 = sp[:framestyle] in (:origin, :zerolines) ? (namin, namax) : (na0, na1)
|
||||
for tick in ticks[1]
|
||||
if ax[:showaxis]
|
||||
push!(
|
||||
tick_segments,
|
||||
sort_3d_axes(tick, tick_start, fa0, letter),
|
||||
sort_3d_axes(tick, tick_stop, fa0, letter),
|
||||
)
|
||||
end
|
||||
if ax[:grid]
|
||||
push!(
|
||||
grid_segments,
|
||||
sort_3d_axes(tick, ga0, fa0, letter),
|
||||
sort_3d_axes(tick, ga1, fa0, letter),
|
||||
)
|
||||
push!(
|
||||
grid_segments,
|
||||
sort_3d_axes(tick, ga1, fa0, letter),
|
||||
sort_3d_axes(tick, ga1, fa1, letter),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
if !(ax[:minorticks] in (:none, nothing, false)) || ax[:minorgrid]
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
t = invf(f(0) + 0.006 * (f(namax) - f(namin)))
|
||||
(-t, t)
|
||||
else
|
||||
t = invf(f(na0) + 0.006 * (f(na1) - f(na0)) * ticks_in)
|
||||
(na0, t)
|
||||
end
|
||||
for tick in minor_ticks
|
||||
if ax[:showaxis]
|
||||
push!(
|
||||
tick_segments,
|
||||
sort_3d_axes(tick, tick_start, fa0, letter),
|
||||
sort_3d_axes(tick, tick_stop, fa0, letter),
|
||||
)
|
||||
end
|
||||
if ax[:minorgrid]
|
||||
push!(
|
||||
minorgrid_segments,
|
||||
sort_3d_axes(tick, ga0, fa0, letter),
|
||||
sort_3d_axes(tick, ga1, fa0, letter),
|
||||
)
|
||||
push!(
|
||||
minorgrid_segments,
|
||||
sort_3d_axes(tick, ga1, fa0, letter),
|
||||
sort_3d_axes(tick, ga1, fa1, letter),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return (
|
||||
ticks = ticks,
|
||||
segments = segments,
|
||||
tick_segments = tick_segments,
|
||||
grid_segments = grid_segments,
|
||||
minorgrid_segments = minorgrid_segments,
|
||||
border_segments = border_segments
|
||||
)
|
||||
end
|
||||
|
||||
reverse_if(x, cond) = cond ? reverse(x) : x
|
||||
axis_tuple(x, y, letter) = reverse_if((x, y), letter === :y)
|
||||
|
||||
axes_shift(t, i) = i % 3 == 0 ? t : i % 3 == 1 ? (t[3], t[1], t[2]) : (t[2], t[3], t[1])
|
||||
@@ -0,0 +1,855 @@
|
||||
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}()
|
||||
const _default_backends = (:none, :gr, :plotly)
|
||||
|
||||
const _backend_packages = Dict{Symbol, Symbol}()
|
||||
|
||||
"Returns a list of supported backends"
|
||||
backends() = _backends
|
||||
|
||||
"Returns the name of the current backend"
|
||||
backend_name() = CURRENT_BACKEND.sym
|
||||
|
||||
function _backend_instance(sym::Symbol)::AbstractBackend
|
||||
haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
|
||||
end
|
||||
|
||||
backend_package_name(sym::Symbol) = _backend_packages[sym]
|
||||
|
||||
macro init_backend(s)
|
||||
package_str = string(s)
|
||||
str = lowercase(package_str)
|
||||
sym = Symbol(str)
|
||||
T = Symbol(string(s) * "Backend")
|
||||
esc(quote
|
||||
struct $T <: AbstractBackend end
|
||||
export $sym
|
||||
$sym(; kw...) = (default(; reset = false, kw...); backend($T()))
|
||||
backend_name(::$T) = Symbol($str)
|
||||
backend_package_name(pkg::$T) = backend_package_name(Symbol($str))
|
||||
push!(_backends, Symbol($str))
|
||||
_backendType[Symbol($str)] = $T
|
||||
_backendSymbol[$T] = Symbol($str)
|
||||
_backend_packages[Symbol($str)] = Symbol($package_str)
|
||||
end)
|
||||
end
|
||||
|
||||
# include("backends/web.jl")
|
||||
# include("backends/supported.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# don't do anything as a default
|
||||
_create_backend_figure(plt::Plot) = nothing
|
||||
_prepare_plot_object(plt::Plot) = nothing
|
||||
_initialize_subplot(plt::Plot, sp::Subplot) = nothing
|
||||
|
||||
_series_added(plt::Plot, series::Series) = nothing
|
||||
_series_updated(plt::Plot, series::Series) = nothing
|
||||
|
||||
_before_layout_calcs(plt::Plot) = nothing
|
||||
|
||||
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)
|
||||
# we need to compute the size of the ticks generically
|
||||
# this means computing the bounding box and then getting the width/height
|
||||
# note:
|
||||
ptsz = sz * pt
|
||||
width = 0.8lablen * ptsz
|
||||
|
||||
# now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||
height = abs(sind(rot)) * width + abs(cosd(rot)) * ptsz
|
||||
width = abs(sind(rot+90)) * width + abs(cosd(rot+90)) * ptsz
|
||||
width, height
|
||||
end
|
||||
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
|
||||
|
||||
# account for the size/length/rotation of tick labels
|
||||
function tick_padding(sp::Subplot, axis::Axis)
|
||||
ticks = get_ticks(sp, axis)
|
||||
if ticks === nothing
|
||||
0mm
|
||||
else
|
||||
vals, labs = ticks
|
||||
isempty(labs) && return 0mm
|
||||
# ptsz = axis[:tickfont].pointsize * pt
|
||||
longest_label = maximum(length(lab) for lab in labs)
|
||||
|
||||
# generalize by "rotating" y labels
|
||||
rot = axis[:rotation] + (axis[:letter] == :y ? 90 : 0)
|
||||
|
||||
# # we need to compute the size of the ticks generically
|
||||
# # this means computing the bounding box and then getting the width/height
|
||||
# labelwidth = 0.8longest_label * ptsz
|
||||
#
|
||||
#
|
||||
# # now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||
# hgt = abs(sind(rot)) * labelwidth + abs(cosd(rot)) * ptsz + 1mm
|
||||
# hgt
|
||||
|
||||
# get the height of the rotated label
|
||||
text_size(longest_label, axis[:tickfontsize], rot)[2]
|
||||
end
|
||||
end
|
||||
|
||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot)
|
||||
# TODO: something different when `RecipesPipeline.is3d(sp) == true`
|
||||
leftpad = tick_padding(sp, sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
|
||||
toppad = sp[:top_margin] + title_padding(sp)
|
||||
rightpad = sp[:right_margin]
|
||||
bottompad = tick_padding(sp, sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
|
||||
|
||||
# switch them?
|
||||
if sp[:xaxis][:mirror]
|
||||
bottompad, toppad = toppad, bottompad
|
||||
end
|
||||
if sp[:yaxis][:mirror]
|
||||
leftpad, rightpad = rightpad, leftpad
|
||||
end
|
||||
|
||||
# @show (leftpad, toppad, rightpad, bottompad)
|
||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||
end
|
||||
|
||||
_update_plot_object(plt::Plot) = nothing
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
mutable struct CurrentBackend
|
||||
sym::Symbol
|
||||
pkg::AbstractBackend
|
||||
end
|
||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
_fallback_default_backend() = backend(GRBackend())
|
||||
|
||||
function _pick_default_backend()
|
||||
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
|
||||
if env_default != ""
|
||||
sym = Symbol(lowercase(env_default))
|
||||
if sym in _backends
|
||||
backend(sym)
|
||||
else
|
||||
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t" *
|
||||
join(sort(_backends), "\n\t"))
|
||||
_fallback_default_backend()
|
||||
end
|
||||
else
|
||||
_fallback_default_backend()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
"""
|
||||
Returns the current plotting package name. Initializes package on first call.
|
||||
"""
|
||||
function backend()
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
_pick_default_backend()
|
||||
end
|
||||
|
||||
CURRENT_BACKEND.pkg
|
||||
end
|
||||
|
||||
"""
|
||||
Set the plot backend.
|
||||
"""
|
||||
function backend(pkg::AbstractBackend)
|
||||
sym = backend_name(pkg)
|
||||
if !(sym in _initialized_backends)
|
||||
_initialize_backend(pkg)
|
||||
push!(_initialized_backends, sym)
|
||||
end
|
||||
CURRENT_BACKEND.sym = sym
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
pkg
|
||||
end
|
||||
|
||||
function backend(sym::Symbol)
|
||||
if sym in _backends
|
||||
backend(_backend_instance(sym))
|
||||
else
|
||||
@warn("`:$sym` is not a supported backend.")
|
||||
backend()
|
||||
end
|
||||
end
|
||||
|
||||
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize, :pgfplots]
|
||||
|
||||
function warn_on_deprecated_backend(bsym::Symbol)
|
||||
if bsym in _deprecated_backends
|
||||
if bsym == :pgfplots
|
||||
@warn("Backend $bsym has been deprecated. Use pgfplotsx instead.")
|
||||
else
|
||||
@warn("Backend $bsym has been deprecated.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# these are args which every backend supports because they're not used in the backend code
|
||||
const _base_supported_args = [
|
||||
:color_palette,
|
||||
:background_color, :background_color_subplot,
|
||||
:foreground_color, :foreground_color_subplot,
|
||||
:group,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:smooth,
|
||||
:xerror, :yerror, :zerror,
|
||||
:subplot,
|
||||
:x, :y, :z,
|
||||
:show, :size,
|
||||
:margin,
|
||||
:left_margin,
|
||||
:right_margin,
|
||||
:top_margin,
|
||||
:bottom_margin,
|
||||
:html_output_format,
|
||||
:layout,
|
||||
:link,
|
||||
:primary,
|
||||
:series_annotations,
|
||||
:subplot_index,
|
||||
:discrete_values,
|
||||
:projection,
|
||||
:show_empty_bins
|
||||
]
|
||||
|
||||
function merge_with_base_supported(v::AVec)
|
||||
v = vcat(v, _base_supported_args)
|
||||
for vi in v
|
||||
if haskey(_axis_defaults, vi)
|
||||
for letter in (:x,:y,:z)
|
||||
push!(v, Symbol(letter,vi))
|
||||
end
|
||||
end
|
||||
end
|
||||
Set(v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
@init_backend PyPlot
|
||||
@init_backend UnicodePlots
|
||||
@init_backend Plotly
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend PGFPlots
|
||||
@init_backend PGFPlotsX
|
||||
@init_backend InspectDR
|
||||
@init_backend HDF5
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# create the various `is_xxx_supported` and `supported_xxxs` methods
|
||||
# by default they pass through to checking membership in `_gr_xxx`
|
||||
for s in (:attr, :seriestype, :marker, :style, :scale)
|
||||
f = Symbol("is_", s, "_supported")
|
||||
f2 = Symbol("supported_", s, "s")
|
||||
@eval begin
|
||||
$f(::AbstractBackend, $s) = false
|
||||
$f(bend::AbstractBackend, $s::AbstractVector) = all(v -> $f(bend, v), $s)
|
||||
$f($s) = $f(backend(), $s)
|
||||
$f2() = $f2(backend())
|
||||
end
|
||||
|
||||
for bend in backends()
|
||||
bend_type = typeof(_backend_instance(bend))
|
||||
v = Symbol("_", bend, "_", s)
|
||||
@eval begin
|
||||
$f(::$bend_type, $s::Symbol) = $s in $v
|
||||
$f2(::$bend_type) = $v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# is_subplot_supported(::AbstractBackend) = false
|
||||
# is_subplot_supported() = is_subplot_supported(backend())
|
||||
|
||||
|
||||
################################################################################
|
||||
# initialize the backends
|
||||
|
||||
function _initialize_backend(pkg::AbstractBackend)
|
||||
sym = backend_package_name(pkg)
|
||||
@eval Main begin
|
||||
import $sym
|
||||
export $sym
|
||||
end
|
||||
end
|
||||
|
||||
_initialize_backend(pkg::GRBackend) = nothing
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# gr
|
||||
|
||||
const _gr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:layout,
|
||||
:title, :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontrotation, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
|
||||
:legendfontrotation, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
|
||||
:tickfontrotation, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
|
||||
:guidefontrotation, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:aspect_ratio,
|
||||
:normalize, :weights,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _gr_seriestype = [
|
||||
:path,
|
||||
:scatter,
|
||||
:straightline,
|
||||
:heatmap,
|
||||
:image,
|
||||
:contour,
|
||||
:path3d,
|
||||
:scatter3d,
|
||||
:surface,
|
||||
:wireframe,
|
||||
:volume,
|
||||
:shape,
|
||||
]
|
||||
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _gr_marker = _allMarkers
|
||||
const _gr_scale = [:identity, :log10]
|
||||
is_marker_supported(::GRBackend, shape::Shape) = true
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# plotly
|
||||
|
||||
function _initialize_backend(pkg::PlotlyBackend)
|
||||
try
|
||||
@eval Main begin
|
||||
import PlotlyBase
|
||||
end
|
||||
catch
|
||||
@info "For saving to png with the Plotly backend PlotlyBase has to be installed."
|
||||
end
|
||||
end
|
||||
|
||||
const _plotly_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:foreground_color_title,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:title, :titlelocation,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :gridalpha, :gridlinewidth,
|
||||
:legend, :colorbar, :colorbar_title, :colorbar_entry,
|
||||
:marker_z, :fill_z, :line_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
# :contours,
|
||||
:aspect_ratio,
|
||||
:hover,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:clims,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
|
||||
const _plotly_seriestype = [
|
||||
:path,
|
||||
:scatter,
|
||||
:heatmap,
|
||||
:contour,
|
||||
:surface,
|
||||
:wireframe,
|
||||
:path3d,
|
||||
:scatter3d,
|
||||
:shape,
|
||||
:scattergl,
|
||||
:straightline,
|
||||
:mesh3d
|
||||
]
|
||||
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _plotly_marker = [
|
||||
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
|
||||
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
|
||||
]
|
||||
const _plotly_scale = [:identity, :log10]
|
||||
|
||||
defaultOutputFormat(plt::Plot{Plots.PlotlyBackend}) = "html"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pgfplots
|
||||
|
||||
const _pgfplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
# :foreground_color_legend,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
# :bar_width, :bar_edges,
|
||||
:title,
|
||||
# :window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
:colorbar, :colorbar_title,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
:tick_direction,
|
||||
:framestyle,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# plotlyjs
|
||||
|
||||
function _initialize_backend(pkg::PlotlyJSBackend)
|
||||
@eval Main begin
|
||||
import PlotlyJS
|
||||
export PlotlyJS
|
||||
end
|
||||
end
|
||||
|
||||
const _plotlyjs_attr = _plotly_attr
|
||||
const _plotlyjs_seriestype = _plotly_seriestype
|
||||
const _plotlyjs_style = _plotly_style
|
||||
const _plotlyjs_marker = _plotly_marker
|
||||
const _plotlyjs_scale = _plotly_scale
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pyplot
|
||||
|
||||
function _initialize_backend(::PyPlotBackend)
|
||||
@eval Main begin
|
||||
import PyPlot
|
||||
|
||||
export PyPlot
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
end
|
||||
end
|
||||
|
||||
const _pyplot_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :titlelocation, :titlefont,
|
||||
:window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:stride,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
:path,
|
||||
:steppre,
|
||||
:steppost,
|
||||
:shape,
|
||||
:straightline,
|
||||
:scatter,
|
||||
:hexbin,
|
||||
:heatmap,
|
||||
:image,
|
||||
:contour,
|
||||
:contour3d,
|
||||
:path3d,
|
||||
:scatter3d,
|
||||
:surface,
|
||||
:wireframe,
|
||||
]
|
||||
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _pyplot_marker = vcat(_allMarkers, :pixel)
|
||||
const _pyplot_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# unicodeplots
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor,
|
||||
:seriesalpha,
|
||||
:linestyle,
|
||||
:markershape,
|
||||
:bins,
|
||||
:title,
|
||||
:guide, :lims,
|
||||
])
|
||||
const _unicodeplots_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
# :bar,
|
||||
:shape,
|
||||
:histogram2d,
|
||||
:spy
|
||||
]
|
||||
const _unicodeplots_style = [:auto, :solid]
|
||||
const _unicodeplots_marker = [:none, :auto, :circle]
|
||||
const _unicodeplots_scale = [:identity]
|
||||
|
||||
# Additional constants
|
||||
const _canvas_type = Ref(:auto)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# hdf5
|
||||
|
||||
const _hdf5_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :titlelocation, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
])
|
||||
const _hdf5_seriestype = [
|
||||
:path,
|
||||
:steppre,
|
||||
:steppost,
|
||||
:shape,
|
||||
:straightline,
|
||||
:scatter,
|
||||
:hexbin,
|
||||
:heatmap,
|
||||
:image,
|
||||
:contour,
|
||||
:contour3d,
|
||||
:path3d,
|
||||
:scatter3d,
|
||||
:surface,
|
||||
:wireframe,
|
||||
]
|
||||
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _hdf5_marker = vcat(_allMarkers, :pixel)
|
||||
const _hdf5_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# Additional constants
|
||||
#Dict has problems using "Types" as keys. Initialize in "_initialize_backend":
|
||||
const HDF5PLOT_MAP_STR2TELEM = Dict{String, Type}()
|
||||
const HDF5PLOT_MAP_TELEM2STR = Dict{Type, String}()
|
||||
|
||||
#Don't really like this global variable... Very hacky
|
||||
mutable struct HDF5Plot_PlotRef
|
||||
ref::Union{Plot, Nothing}
|
||||
end
|
||||
const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# inspectdr
|
||||
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_grid,
|
||||
:foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokestyle, #Causes warning not to have it... what is this?
|
||||
:fillcolor, :fillalpha, #:fillrange,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :titlelocation,
|
||||
:window_title,
|
||||
:guide, :lims, :scale, #:ticks, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :legend, #:colorbar,
|
||||
# :marker_z,
|
||||
# :line_z,
|
||||
# :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
:dpi,
|
||||
# :colorbar_title,
|
||||
])
|
||||
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _inspectdr_seriestype = [
|
||||
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
|
||||
]
|
||||
#see: _allMarkers, _shape_keys
|
||||
const _inspectdr_marker = Symbol[
|
||||
:none, :auto,
|
||||
:circle, :rect, :diamond,
|
||||
:cross, :xcross,
|
||||
:utriangle, :dtriangle, :rtriangle, :ltriangle,
|
||||
:pentagon, :hexagon, :heptagon, :octagon,
|
||||
:star4, :star5, :star6, :star7, :star8,
|
||||
:vline, :hline, :+, :x,
|
||||
]
|
||||
|
||||
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
||||
# ------------------------------------------------------------------------------
|
||||
# pgfplotsx
|
||||
|
||||
const _pgfplotsx_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend,
|
||||
:background_color_inside,
|
||||
:background_color_outside,
|
||||
:foreground_color_legend,
|
||||
:foreground_color_grid,
|
||||
:foreground_color_axis,
|
||||
:foreground_color_text,
|
||||
:foreground_color_border,
|
||||
:label,
|
||||
:seriescolor,
|
||||
:seriesalpha,
|
||||
:linecolor,
|
||||
:linestyle,
|
||||
:linewidth,
|
||||
:linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markeralpha,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
:markerstrokealpha,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:fillalpha,
|
||||
:bins,
|
||||
:layout,
|
||||
:title,
|
||||
:window_title,
|
||||
:guide,
|
||||
:lims,
|
||||
:ticks,
|
||||
:scale,
|
||||
:flip,
|
||||
:titlefontfamily,
|
||||
:titlefontsize,
|
||||
:titlefonthalign,
|
||||
:titlefontvalign,
|
||||
:titlefontrotation,
|
||||
:titlefontcolor,
|
||||
:legendfontfamily,
|
||||
:legendfontsize,
|
||||
:legendfonthalign,
|
||||
:legendfontvalign,
|
||||
:legendfontrotation,
|
||||
:legendfontcolor,
|
||||
:tickfontfamily,
|
||||
:tickfontsize,
|
||||
:tickfonthalign,
|
||||
:tickfontvalign,
|
||||
:tickfontrotation,
|
||||
:tickfontcolor,
|
||||
:guidefontfamily,
|
||||
:guidefontsize,
|
||||
:guidefonthalign,
|
||||
:guidefontvalign,
|
||||
:guidefontrotation,
|
||||
:guidefontcolor,
|
||||
:grid,
|
||||
:gridalpha,
|
||||
:gridstyle,
|
||||
:gridlinewidth,
|
||||
:legend,
|
||||
:legendtitle,
|
||||
:colorbar,
|
||||
:colorbar_title,
|
||||
:colorbar_entry,
|
||||
:fill_z,
|
||||
:line_z,
|
||||
:marker_z,
|
||||
:levels,
|
||||
:ribbon,
|
||||
:quiver,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:aspect_ratio,
|
||||
:normalize,
|
||||
:weights,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pgfplotsx_seriestype = [
|
||||
:path,
|
||||
:scatter,
|
||||
:straightline,
|
||||
:path3d,
|
||||
:scatter3d,
|
||||
:surface,
|
||||
:wireframe,
|
||||
:heatmap,
|
||||
:mesh3d,
|
||||
:contour,
|
||||
:contour3d,
|
||||
:quiver,
|
||||
:shape,
|
||||
:steppre,
|
||||
:stepmid,
|
||||
:steppost,
|
||||
:ysticks,
|
||||
:xsticks,
|
||||
]
|
||||
const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplotsx_marker = [
|
||||
:none,
|
||||
:auto,
|
||||
:circle,
|
||||
:rect,
|
||||
:diamond,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:ltriangle,
|
||||
:rtriangle,
|
||||
:cross,
|
||||
:xcross,
|
||||
:star5,
|
||||
:pentagon,
|
||||
:hline,
|
||||
:vline,
|
||||
Shape,
|
||||
]
|
||||
const _pgfplotsx_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true
|
||||
|
||||
# additional constants
|
||||
const _pgfplotsx_series_ids = KW()
|
||||
@@ -0,0 +1,600 @@
|
||||
# https://github.com/sisl/PGFPlots.jl
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
const _pgfplots_linestyles = KW(
|
||||
:solid => "solid",
|
||||
:dash => "dashed",
|
||||
:dot => "dotted",
|
||||
:dashdot => "dashdotted",
|
||||
:dashdotdot => "dashdotdotted",
|
||||
)
|
||||
|
||||
const _pgfplots_markers = KW(
|
||||
:none => "none",
|
||||
:cross => "+",
|
||||
:xcross => "x",
|
||||
:+ => "+",
|
||||
:x => "x",
|
||||
:utriangle => "triangle*",
|
||||
:dtriangle => "triangle*",
|
||||
:circle => "*",
|
||||
:rect => "square*",
|
||||
:star5 => "star",
|
||||
:star6 => "asterisk",
|
||||
:diamond => "diamond*",
|
||||
:pentagon => "pentagon*",
|
||||
:hline => "-",
|
||||
:vline => "|"
|
||||
)
|
||||
|
||||
const _pgfplots_legend_pos = KW(
|
||||
:bottomleft => "south west",
|
||||
:bottomright => "south east",
|
||||
:topright => "north east",
|
||||
:topleft => "north west",
|
||||
:outertopright => "outer north east",
|
||||
)
|
||||
|
||||
|
||||
const _pgf_series_extrastyle = KW(
|
||||
:steppre => "const plot mark right",
|
||||
:stepmid => "const plot mark mid",
|
||||
:steppost => "const plot",
|
||||
:sticks => "ycomb",
|
||||
:ysticks => "ycomb",
|
||||
:xsticks => "xcomb",
|
||||
)
|
||||
|
||||
# PGFPlots uses the anchors to define orientations for example to align left
|
||||
# one needs to use the right edge as anchor
|
||||
const _pgf_annotation_halign = KW(
|
||||
:center => "",
|
||||
:left => "right",
|
||||
: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
|
||||
function pgf_color(c::Colorant)
|
||||
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", red(c), green(c), blue(c))
|
||||
cstr, alpha(c)
|
||||
end
|
||||
|
||||
function pgf_color(grad::ColorGradient)
|
||||
# Can't handle ColorGradient here, fallback to defaults.
|
||||
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316,0.97868012)
|
||||
cstr, 1
|
||||
end
|
||||
|
||||
# Generates a colormap for pgfplots based on a ColorGradient
|
||||
function pgf_colormap(grad::ColorGradient)
|
||||
join(map(grad.colors) do c
|
||||
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
|
||||
end,", ")
|
||||
end
|
||||
|
||||
pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
|
||||
pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
|
||||
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
|
||||
|
||||
function pgf_fillstyle(plotattributes, i = 1)
|
||||
cstr,a = pgf_color(get_fillcolor(plotattributes, i))
|
||||
fa = get_fillalpha(plotattributes, i)
|
||||
if fa !== nothing
|
||||
a = fa
|
||||
end
|
||||
"fill = $cstr, fill opacity=$a"
|
||||
end
|
||||
|
||||
function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
|
||||
cstr, a = pgf_color(plot_color(color, α))
|
||||
"""
|
||||
color = $cstr,
|
||||
draw opacity = $a,
|
||||
line width = $linewidth,
|
||||
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
|
||||
end
|
||||
|
||||
function pgf_linestyle(plotattributes, i = 1)
|
||||
lw = pgf_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i)
|
||||
lc = get_linecolor(plotattributes, i)
|
||||
la = get_linealpha(plotattributes, i)
|
||||
ls = get_linestyle(plotattributes, i)
|
||||
return pgf_linestyle(lw, lc, la, ls)
|
||||
end
|
||||
|
||||
function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
|
||||
fs = fontsize * thickness_scaling
|
||||
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
|
||||
end
|
||||
|
||||
function pgf_marker(plotattributes, i = 1)
|
||||
shape = _cycle(plotattributes[:markershape], i)
|
||||
cstr, a = pgf_color(plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)))
|
||||
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)))
|
||||
return string(
|
||||
"mark = $(get(_pgfplots_markers, shape, "*")),\n",
|
||||
"mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),\n",
|
||||
plotattributes[:seriestype] == :scatter ? "only marks,\n" : "",
|
||||
"mark options = {
|
||||
color = $cstr_stroke, draw opacity = $a_stroke,
|
||||
fill = $cstr, fill opacity = $a,
|
||||
line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)),
|
||||
rotate = $(shape == :dtriangle ? 180 : 0),
|
||||
$(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid"))
|
||||
}"
|
||||
)
|
||||
end
|
||||
|
||||
function pgf_add_annotation!(o, x, y, val, thickness_scaling = 1)
|
||||
# Construct the style string.
|
||||
# Currently supports color and orientation
|
||||
cstr,a = pgf_color(val.font.color)
|
||||
push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text
|
||||
x, y,
|
||||
style="""
|
||||
$(get(_pgf_annotation_halign,val.font.halign,"")),
|
||||
color=$cstr, draw opacity=$(convert(Float16,a)),
|
||||
rotate=$(val.font.rotation),
|
||||
font=$(pgf_font(val.font.pointsize, thickness_scaling))
|
||||
"""))
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function pgf_series(sp::Subplot, series::Series)
|
||||
plotattributes = series.plotattributes
|
||||
st = plotattributes[:seriestype]
|
||||
series_collection = PGFPlots.Plot[]
|
||||
|
||||
# function args
|
||||
args = if st == :contour
|
||||
plotattributes[:z].surf, plotattributes[:x], plotattributes[:y]
|
||||
elseif RecipesPipeline.is3d(st)
|
||||
plotattributes[:x], plotattributes[:y], plotattributes[:z]
|
||||
elseif st == :straightline
|
||||
straightline_data(series)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
elseif ispolar(sp)
|
||||
theta, r = plotattributes[:x], plotattributes[:y]
|
||||
rad2deg.(theta), r
|
||||
else
|
||||
plotattributes[:x], plotattributes[:y]
|
||||
end
|
||||
|
||||
# PGFPlots can't handle non-Vector?
|
||||
# args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
|
||||
# collect(a)
|
||||
# else
|
||||
# a
|
||||
# end, args)
|
||||
|
||||
if st in (:contour, :histogram2d)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(plotattributes))
|
||||
push!(style, pgf_marker(plotattributes))
|
||||
push!(style, "forget plot")
|
||||
|
||||
kw[:style] = join(style, ',')
|
||||
func = if st == :histogram2d
|
||||
PGFPlots.Histogram2
|
||||
else
|
||||
kw[:labels] = series[:contour_labels]
|
||||
kw[:levels] = series[:levels]
|
||||
PGFPlots.Contour
|
||||
end
|
||||
push!(series_collection, func(args...; kw...))
|
||||
|
||||
else
|
||||
# series segments
|
||||
segments = iter_segments(series)
|
||||
for (i, rng) in enumerate(segments)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(plotattributes, i))
|
||||
push!(style, pgf_marker(plotattributes, i))
|
||||
|
||||
if st == :shape
|
||||
push!(style, pgf_fillstyle(plotattributes, i))
|
||||
end
|
||||
|
||||
# add to legend?
|
||||
if i == 1 && sp[:legend] != :none && should_add_to_legend(series)
|
||||
if plotattributes[:fillrange] !== nothing
|
||||
push!(style, "forget plot")
|
||||
push!(series_collection, pgf_fill_legend_hack(plotattributes, args))
|
||||
else
|
||||
kw[:legendentry] = plotattributes[:label]
|
||||
if st == :shape # || plotattributes[:fillrange] !== nothing
|
||||
push!(style, "area legend")
|
||||
end
|
||||
end
|
||||
else
|
||||
push!(style, "forget plot")
|
||||
end
|
||||
|
||||
seg_args = (arg[rng] for arg in args)
|
||||
|
||||
# include additional style, then add to the kw
|
||||
if haskey(_pgf_series_extrastyle, st)
|
||||
push!(style, _pgf_series_extrastyle[st])
|
||||
end
|
||||
kw[:style] = join(style, ',')
|
||||
|
||||
# add fillrange
|
||||
if series[:fillrange] !== nothing && st != :shape
|
||||
push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...))
|
||||
end
|
||||
|
||||
# build/return the series object
|
||||
func = if st == :path3d
|
||||
PGFPlots.Linear3
|
||||
elseif st == :scatter
|
||||
PGFPlots.Scatter
|
||||
else
|
||||
PGFPlots.Linear
|
||||
end
|
||||
push!(series_collection, func(seg_args...; kw...))
|
||||
end
|
||||
end
|
||||
series_collection
|
||||
end
|
||||
|
||||
function pgf_fillrange_series(series, i, fillrange, args...)
|
||||
st = series[:seriestype]
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, "line width = 0")
|
||||
push!(style, "draw opacity = 0")
|
||||
push!(style, pgf_fillstyle(series, i))
|
||||
push!(style, pgf_marker(series, i))
|
||||
push!(style, "forget plot")
|
||||
if haskey(_pgf_series_extrastyle, st)
|
||||
push!(style, _pgf_series_extrastyle[st])
|
||||
end
|
||||
kw[:style] = join(style, ',')
|
||||
func = RecipesPipeline.is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear
|
||||
return func(pgf_fillrange_args(fillrange, args...)...; kw...)
|
||||
end
|
||||
|
||||
function pgf_fillrange_args(fillrange, x, y)
|
||||
n = length(x)
|
||||
x_fill = [x; x[n:-1:1]; x[1]]
|
||||
y_fill = [y; _cycle(fillrange, n:-1:1); y[1]]
|
||||
return x_fill, y_fill
|
||||
end
|
||||
|
||||
function pgf_fillrange_args(fillrange, x, y, z)
|
||||
n = length(x)
|
||||
x_fill = [x; x[n:-1:1]; x[1]]
|
||||
y_fill = [y; y[n:-1:1]; x[1]]
|
||||
z_fill = [z; _cycle(fillrange, n:-1:1); z[1]]
|
||||
return x_fill, y_fill, z_fill
|
||||
end
|
||||
|
||||
function pgf_fill_legend_hack(plotattributes, args)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(plotattributes, 1))
|
||||
push!(style, pgf_marker(plotattributes, 1))
|
||||
push!(style, pgf_fillstyle(plotattributes, 1))
|
||||
push!(style, "area legend")
|
||||
kw[:legendentry] = plotattributes[:label]
|
||||
kw[:style] = join(style, ',')
|
||||
st = plotattributes[:seriestype]
|
||||
func = if st == :path3d
|
||||
PGFPlots.Linear3
|
||||
elseif st == :scatter
|
||||
PGFPlots.Scatter
|
||||
else
|
||||
PGFPlots.Linear
|
||||
end
|
||||
return func(([arg[1]] for arg in args)...; kw...)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function pgf_axis(sp::Subplot, letter)
|
||||
axis = sp[Symbol(letter,:axis)]
|
||||
style = []
|
||||
kw = KW()
|
||||
|
||||
# turn off scaled ticks
|
||||
push!(style, "scaled $(letter) ticks = false")
|
||||
|
||||
# set to supported framestyle
|
||||
framestyle = pgf_framestyle(sp[:framestyle])
|
||||
|
||||
# axis guide
|
||||
kw[Symbol(letter,:label)] = axis[:guide]
|
||||
|
||||
# axis label position
|
||||
labelpos = ""
|
||||
if letter == :x && axis[:guide_position] == :top
|
||||
labelpos = "at={(0.5,1)},above,"
|
||||
elseif letter == :y && axis[:guide_position] == :right
|
||||
labelpos = "at={(1,0.5)},below,"
|
||||
end
|
||||
|
||||
# Add label font
|
||||
cstr, α = pgf_color(plot_color(axis[:guidefontcolor]))
|
||||
push!(style, string(letter, "label style = {", labelpos ,"font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}"))
|
||||
|
||||
# flip/reverse?
|
||||
axis[:flip] && push!(style, "$letter dir=reverse")
|
||||
|
||||
# scale
|
||||
scale = axis[:scale]
|
||||
if scale in (:log2, :ln, :log10)
|
||||
kw[Symbol(letter,:mode)] = "log"
|
||||
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
|
||||
end
|
||||
|
||||
# ticks on or off
|
||||
if axis[:ticks] in (nothing, false, :none) || framestyle == :none
|
||||
push!(style, "$(letter)majorticks=false")
|
||||
end
|
||||
|
||||
# grid on or off
|
||||
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 = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||
ticks = get_ticks(sp, axis)
|
||||
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
|
||||
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
|
||||
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
|
||||
# wrap the power part of label with }
|
||||
tick_labels = Vector{String}(undef, length(ticks[2]))
|
||||
for (i, label) in enumerate(ticks[2])
|
||||
base, power = split(label, "^")
|
||||
power = string("{", power, "}")
|
||||
tick_labels[i] = string(base, "^", power)
|
||||
end
|
||||
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
|
||||
elseif axis[:showaxis]
|
||||
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
|
||||
if axis[:formatter] in (:scientific, :auto)
|
||||
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
|
||||
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
|
||||
end
|
||||
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
|
||||
else
|
||||
push!(style, string(letter, "ticklabels = {}"))
|
||||
end
|
||||
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
|
||||
cstr, α = pgf_color(plot_color(axis[:tickfontcolor]))
|
||||
push!(style, string(letter, "ticklabel style = {font = ", pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:tickfontrotation], "}"))
|
||||
push!(style, string(letter, " grid style = {", pgf_linestyle(pgf_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]), "}"))
|
||||
end
|
||||
|
||||
# framestyle
|
||||
if framestyle in (:axes, :origin)
|
||||
axispos = framestyle == :axes ? "left" : "middle"
|
||||
if axis[:draw_arrow]
|
||||
push!(style, string("axis ", letter, " line = ", axispos))
|
||||
else
|
||||
# the * after line disables the arrow at the axis
|
||||
push!(style, string("axis ", letter, " line* = ", axispos))
|
||||
end
|
||||
end
|
||||
|
||||
if framestyle == :zerolines
|
||||
push!(style, string("extra ", letter, " ticks = 0"))
|
||||
push!(style, string("extra ", letter, " tick labels = "))
|
||||
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}"))
|
||||
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}"))
|
||||
else
|
||||
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}"))
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
style, kw
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
plt.o = PGFPlots.Axis[]
|
||||
# Obtain the total height of the plot by extracting the maximal bottom
|
||||
# coordinate from the bounding box.
|
||||
total_height = bottom(bbox(plt.layout))
|
||||
|
||||
for sp in plt.subplots
|
||||
# first build the PGFPlots.Axis object
|
||||
style = ["unbounded coords=jump"]
|
||||
kw = KW()
|
||||
|
||||
# add to style/kw for each axis
|
||||
for letter in (:x, :y, :z)
|
||||
if letter != :z || RecipesPipeline.is3d(sp)
|
||||
axisstyle, axiskw = pgf_axis(sp, letter)
|
||||
append!(style, axisstyle)
|
||||
merge!(kw, axiskw)
|
||||
end
|
||||
end
|
||||
|
||||
# bounding box values are in mm
|
||||
# note: bb origin is top-left, pgf is bottom-left
|
||||
# A round on 2 decimal places should be enough precision for 300 dpi
|
||||
# plots.
|
||||
bb = bbox(sp)
|
||||
push!(style, """
|
||||
xshift = $(left(bb).value)mm,
|
||||
yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm,
|
||||
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
|
||||
""")
|
||||
kw[:width] = "$(width(bb).value)mm"
|
||||
kw[:height] = "$(height(bb).value)mm"
|
||||
|
||||
if sp[:title] != ""
|
||||
kw[:title] = "$(sp[:title])"
|
||||
cstr, α = pgf_color(plot_color(sp[:titlefontcolor]))
|
||||
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
|
||||
end
|
||||
|
||||
if get_aspect_ratio(sp) in (1, :equal)
|
||||
kw[:axisEqual] = "true"
|
||||
end
|
||||
|
||||
legpos = sp[:legend]
|
||||
if haskey(_pgfplots_legend_pos, legpos)
|
||||
kw[:legendPos] = _pgfplots_legend_pos[legpos]
|
||||
end
|
||||
cstr, bg_alpha = pgf_color(plot_color(sp[:background_color_legend]))
|
||||
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
|
||||
|
||||
push!(style, string(
|
||||
"legend style = {",
|
||||
pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid", ), ",",
|
||||
"fill = $cstr,",
|
||||
"fill opacity = $bg_alpha,",
|
||||
"text opacity = $(alpha(plot_color(sp[:legendfontcolor]))),",
|
||||
"font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)),
|
||||
"}",
|
||||
))
|
||||
|
||||
if any(s[:seriestype] == :contour for s in series_list(sp))
|
||||
kw[:view] = "{0}{90}"
|
||||
kw[:colorbar] = !(sp[:colorbar] in (:none, :off, :hide, false))
|
||||
elseif RecipesPipeline.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
|
||||
# the colorbar and colomap.
|
||||
# The reasoning behind doing this on the axis level is that pgfplots
|
||||
# colorbar seems to only works on axis level and needs the proper colormap for
|
||||
# correctly displaying it.
|
||||
# It's also possible to assign the colormap to the series itself but
|
||||
# then the colormap needs to be added twice, once for the axis and once for the
|
||||
# series.
|
||||
# As it is likely that all series within the same axis use the same
|
||||
# colormap this should not cause any problem.
|
||||
for series in series_list(sp)
|
||||
for col in (:markercolor, :fillcolor, :linecolor)
|
||||
if typeof(series.plotattributes[col]) == ColorGradient
|
||||
push!(style,"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}")
|
||||
|
||||
if sp[:colorbar] == :none
|
||||
kw[:colorbar] = "false"
|
||||
else
|
||||
kw[:colorbar] = "true"
|
||||
end
|
||||
# goto is needed to break out of col and series for
|
||||
@goto colorbar_end
|
||||
end
|
||||
end
|
||||
end
|
||||
@label colorbar_end
|
||||
|
||||
push!(style, "colorbar style={title=$(sp[:colorbar_title])}")
|
||||
o = axisf(; style = join(style, ","), kw...)
|
||||
|
||||
# add the series object to the PGFPlots.Axis
|
||||
for series in series_list(sp)
|
||||
push!.(Ref(o), pgf_series(sp, series))
|
||||
|
||||
# add series annotations
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
|
||||
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt), pgf_thickness_scaling(series))
|
||||
end
|
||||
end
|
||||
|
||||
# add the annotations
|
||||
for ann in sp[:annotations]
|
||||
pgf_add_annotation!(o, locate_annotation(sp, ann...)..., pgf_thickness_scaling(sp))
|
||||
end
|
||||
|
||||
|
||||
# add the PGFPlots.Axis to the list
|
||||
push!(plt.o, o)
|
||||
end
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
|
||||
show(io, mime, plt.o)
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
# prepare the object
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save a pdf
|
||||
fn = tempname()*".pdf"
|
||||
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
|
||||
|
||||
# read it into io
|
||||
write(io, read(open(fn), String))
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
|
||||
fn = tempname()*".tex"
|
||||
PGFPlots.save(fn, backend_object(plt), include_preamble=plt.attr[:tex_output_standalone])
|
||||
write(io, read(open(fn), String))
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PGFPlotsBackend})
|
||||
# prepare the object
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save an svg
|
||||
fn = string(tempname(), ".svg")
|
||||
PGFPlots.save(PGFPlots.SVG(fn), pgfplt)
|
||||
|
||||
# show it
|
||||
open_browser_window(fn)
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
@@ -1,137 +0,0 @@
|
||||
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
immutable GadflyPackage <: PlottingPackage end
|
||||
|
||||
gadfly!() = plotter!(:gadfly)
|
||||
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
function plot(pkg::GadflyPackage; kw...)
|
||||
@eval import DataFrames
|
||||
|
||||
plt = Gadfly.Plot()
|
||||
plt.mapping = Dict()
|
||||
plt.data_source = DataFrames.DataFrame()
|
||||
plt.layers = plt.layers[1:0]
|
||||
|
||||
# add the title, axis labels, and theme
|
||||
d = Dict(kw)
|
||||
|
||||
plt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]),
|
||||
Gadfly.Guide.ylabel(d[:ylabel]),
|
||||
Gadfly.Guide.title(d[:title])]
|
||||
|
||||
# add the legend?
|
||||
if d[:legend]
|
||||
unshift!(plt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
|
||||
end
|
||||
|
||||
plt.theme = Gadfly.Theme(background_color = (haskey(d, :background_color) ? d[:background_color] : colorant"white"))
|
||||
|
||||
Plot(plt, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
function getGeomFromLineType(linetype::Symbol, nbins::Int)
|
||||
linetype == :line && return Gadfly.Geom.line
|
||||
linetype == :dots && return Gadfly.Geom.point
|
||||
linetype == :bar && return Gadfly.Geom.bar
|
||||
linetype == :step && return Gadfly.Geom.step
|
||||
linetype == :hist && return Gadfly.Geom.histogram(bincount=nbins)
|
||||
linetype == :none && return Gadfly.Geom.point # change this? are we usually pairing no line with scatterplots?
|
||||
linetype == :sticks && return Gadfly.Geom.bar
|
||||
error("linetype $linetype not currently supported with Gadfly")
|
||||
end
|
||||
|
||||
function getGeoms(linetype::Symbol, marker::Symbol, nbins::Int)
|
||||
geoms = []
|
||||
|
||||
# handle heatmaps (hexbins) specially
|
||||
if linetype in (:heatmap,:hexbin)
|
||||
push!(geoms, Gadfly.Geom.hexbin(xbincount=nbins, ybincount=nbins))
|
||||
else
|
||||
|
||||
# for other linetypes, get the correct Geom
|
||||
push!(geoms, getGeomFromLineType(linetype, nbins))
|
||||
|
||||
# for any marker, add Geom.point
|
||||
if marker != :none
|
||||
push!(geoms, Gadfly.Geom.point)
|
||||
end
|
||||
end
|
||||
|
||||
geoms
|
||||
end
|
||||
|
||||
|
||||
# plot one data series
|
||||
function plot!(::GadflyPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
gfargs = []
|
||||
|
||||
# add the Geoms
|
||||
append!(gfargs, getGeoms(d[:linetype], d[:marker], d[:nbins]))
|
||||
|
||||
# set color, line width, and point size
|
||||
theme = Gadfly.Theme(default_color = d[:color],
|
||||
line_width = d[:width] * Gadfly.px,
|
||||
default_point_size = d[:markersize] * Gadfly.px)
|
||||
push!(gfargs, theme)
|
||||
|
||||
# add a regression line?
|
||||
if d[:reg]
|
||||
push!(gfargs, Gadfly.Geom.smooth(method=:lm))
|
||||
end
|
||||
|
||||
# for histograms, set x=y
|
||||
x = d[d[:linetype] == :hist ? :y : :x]
|
||||
|
||||
# add to the legend
|
||||
if length(plt.o.guides) > 0 && isa(plt.o.guides[1], Gadfly.Guide.ManualColorKey)
|
||||
push!(plt.o.guides[1].labels, d[:label])
|
||||
push!(plt.o.guides[1].colors, d[:color])
|
||||
end
|
||||
|
||||
if d[:axis] != :left
|
||||
warn("Gadly only supports one y axis")
|
||||
end
|
||||
|
||||
# save the kw args
|
||||
push!(plt.seriesargs, d)
|
||||
|
||||
# add the layer to the Gadfly.Plot
|
||||
prepend!(plt.o.layers, Gadfly.layer(unique(gfargs)...; x = x, y = d[:y]))
|
||||
plt
|
||||
end
|
||||
|
||||
function Base.display(::GadflyPackage, plt::Plot)
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
function savepng(::GadflyPackage, plt::PlottingObject, fn::String;
|
||||
w = 6 * Gadfly.inch,
|
||||
h = 4 * Gadfly.inch)
|
||||
Gadfly.draw(Gadfly.PNG(fn, w, h), plt.o)
|
||||
end
|
||||
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# create the underlying object (each backend will do this differently)
|
||||
function buildSubplotObject!(::GadflyPackage, subplt::Subplot)
|
||||
i = 0
|
||||
rows = []
|
||||
for rowcnt in subplt.layout.rowcounts
|
||||
push!(rows, Gadfly.hstack([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
|
||||
i += rowcnt
|
||||
end
|
||||
subplt.o = Gadfly.vstack(rows...)
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::GadflyPackage, subplt::Subplot)
|
||||
display(subplt.o)
|
||||
end
|
||||
@@ -0,0 +1,647 @@
|
||||
#HDF5 Plots: Save/replay plots to/from HDF5
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#==Usage
|
||||
===============================================================================
|
||||
Write to .hdf5 file using:
|
||||
p = plot(...)
|
||||
Plots.hdf5plot_write(p, "plotsave.hdf5")
|
||||
|
||||
Read from .hdf5 file using:
|
||||
pyplot() #Must first select backend
|
||||
pread = Plots.hdf5plot_read("plotsave.hdf5")
|
||||
display(pread)
|
||||
==#
|
||||
|
||||
|
||||
#==TODO
|
||||
===============================================================================
|
||||
1. Support more features.
|
||||
- GridLayout known not to be working.
|
||||
2. Improve error handling.
|
||||
- Will likely crash if file format is off.
|
||||
3. Save data in a folder parallel to "plot".
|
||||
- Will make it easier for users to locate data.
|
||||
- Use HDF5 reference to link data?
|
||||
4. Develop an actual versioned file format.
|
||||
- Should have some form of backward compatibility.
|
||||
- Should be reliable for archival purposes.
|
||||
5. Fix construction of plot object with hdf5plot_read.
|
||||
- Layout doesn't seem to get transferred well (ex: `Plots._examples[40]`).
|
||||
- Not building object correctly when backends do not natively support
|
||||
a certain feature (ex: :steppre)
|
||||
- No support for CategoricalArrays.* structures. But they appear to be
|
||||
brought into `Plots._examples[25,30]` through DataFrames.jl - so we can't
|
||||
really reference them in this code.
|
||||
==#
|
||||
"""
|
||||
_hdf5_implementation
|
||||
|
||||
Create module (namespace) for implementing HDF5 "plots".
|
||||
(Avoid name collisions, while keeping names short)
|
||||
"""
|
||||
module _hdf5_implementation #Tools required to implements HDF5 "plots"
|
||||
|
||||
import Dates
|
||||
|
||||
#Plots.jl imports HDF5 to main:
|
||||
import ..HDF5
|
||||
import ..HDF5: Group, Dataset
|
||||
|
||||
import ..Colors, ..Colorant
|
||||
import ..PlotUtils.ColorSchemes.ColorScheme
|
||||
|
||||
import ..HDF5Backend
|
||||
import ..HDF5PLOT_MAP_STR2TELEM, ..HDF5PLOT_MAP_TELEM2STR
|
||||
import ..HDF5Plot_PlotRef, ..HDF5PLOT_PLOTREF
|
||||
import ..BoundingBox, ..Extrema, ..Length
|
||||
import ..RecipesPipeline.datetimeformatter
|
||||
import ..PlotUtils.ColorPalette, ..PlotUtils.CategoricalColorGradient, ..PlotUtils.ContinuousColorGradient
|
||||
import ..Surface, ..Shape, ..Arrow
|
||||
import ..GridLayout, ..RootLayout
|
||||
import ..Font, ..PlotText, ..SeriesAnnotations
|
||||
import ..Axis, ..Subplot, ..Plot
|
||||
import ..AKW, ..KW, ..DefaultsDict
|
||||
import .._axis_defaults
|
||||
import ..plot, ..plot!
|
||||
|
||||
#Types that already have built-in HDF5 support (just write out natively):
|
||||
const HDF5_SupportedTypes = Union{Number, String}
|
||||
#TODO: Types_HDF5Support
|
||||
|
||||
#Dispatch types:
|
||||
struct CplxTuple; end #Identifies a "complex" tuple structure (not merely numbers)
|
||||
#HDF5 reader will auto-detect type correctly:
|
||||
struct HDF5_AutoDetect; end #See HDF5_SupportedTypes
|
||||
|
||||
|
||||
#==
|
||||
===============================================================================#
|
||||
|
||||
if length(HDF5PLOT_MAP_TELEM2STR) < 1
|
||||
#Possible element types of high-level data types:
|
||||
#(Used to add type information as an HDF5 string attribute)
|
||||
#(Also used to dispatch appropriate read function through _read_typed())
|
||||
_telem2str = Dict{String, Type}(
|
||||
"NOTHING" => Nothing,
|
||||
"SYMBOL" => Symbol,
|
||||
"RGBA" => Colorant, #Write out any Colorant to an #RRGGBBAA string
|
||||
"TUPLE" => Tuple,
|
||||
"CTUPLE" => CplxTuple, #Tuple of complex structures
|
||||
|
||||
"EXTREMA" => Extrema,
|
||||
"LENGTH" => Length,
|
||||
"ARRAY" => Array, #Array{Any} (because Array{T<:Union{Number, String}} natively supported by HDF5)
|
||||
|
||||
#Sub-structure types:
|
||||
"T_DATETIMEFORMATTER" => typeof(datetimeformatter),
|
||||
|
||||
#Sub-structure types:
|
||||
"DEFAULTSDICT" => DefaultsDict,
|
||||
"FONT" => Font,
|
||||
"BOUNDINGBOX" => BoundingBox,
|
||||
"GRIDLAYOUT" => GridLayout,
|
||||
"ROOTLAYOUT" => RootLayout,
|
||||
"SERIESANNOTATIONS" => SeriesAnnotations,
|
||||
"PLOTTEXT" => PlotText,
|
||||
"SHAPE" => Shape,
|
||||
"ARROW" => Arrow,
|
||||
"COLORSCHEME" => ColorScheme,
|
||||
"COLORPALETTE" => ColorPalette,
|
||||
"CONT_COLORGRADIENT" => ContinuousColorGradient,
|
||||
"CAT_COLORGRADIENT" => CategoricalColorGradient,
|
||||
"AXIS" => Axis,
|
||||
"SURFACE" => Surface,
|
||||
"SUBPLOT" => Subplot,
|
||||
)
|
||||
merge!(HDF5PLOT_MAP_STR2TELEM, _telem2str) #Faster to create than push!()??
|
||||
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
|
||||
end
|
||||
|
||||
|
||||
#==Helper functions
|
||||
===============================================================================#
|
||||
|
||||
h5plotpath(plotname::String) = "plots/$plotname"
|
||||
|
||||
#Version info
|
||||
#NOTE: could cache output, but we seem to not want const declarations in backend files.
|
||||
function _get_Plots_versionstr()
|
||||
#Adds to load up time... Maybe a more efficient way??
|
||||
try
|
||||
deps = Pkg.dependencies()
|
||||
uuid = Base.UUID("91a5bcdd-55d7-5caf-9e0b-520d859cae80") #Plots.jl
|
||||
vinfo = deps[uuid].version
|
||||
return "Source: Plots.jl v$vinfo"
|
||||
catch
|
||||
now = string(Dates.now()) #Use time in case it can help recover plot
|
||||
return "Source: Plots.jl v? - $now"
|
||||
end
|
||||
end
|
||||
|
||||
function _hdf5_merge!(dest::AKW, src::AKW)
|
||||
for (k, v) in src
|
||||
if isa(v, Axis)
|
||||
_hdf5_merge!(dest[k].plotattributes, v.plotattributes)
|
||||
else
|
||||
dest[k] = v
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
#_type_for_map returns the type to use with HDF5PLOT_MAP_TELEM2STR[], in case it is not concrete:
|
||||
_type_for_map(::Type{T}) where T = T #Catch-all
|
||||
_type_for_map(::Type{T}) where T<:BoundingBox = BoundingBox
|
||||
_type_for_map(::Type{T}) where T<:ColorScheme = ColorScheme
|
||||
_type_for_map(::Type{T}) where T<:Surface = Surface
|
||||
|
||||
|
||||
#==Read/write things like type name in attributes
|
||||
===============================================================================#
|
||||
function _write_datatype_attr(ds::Union{Group, Dataset}, ::Type{T}) where T
|
||||
typestr = HDF5PLOT_MAP_TELEM2STR[T]
|
||||
HDF5.attributes(ds)["TYPE"] = typestr
|
||||
end
|
||||
function _read_datatype_attr(ds::Union{Group, Dataset})
|
||||
if !Base.haskey(HDF5.attributes(ds), "TYPE")
|
||||
return HDF5_AutoDetect
|
||||
end
|
||||
|
||||
typestr = HDF5.read(HDF5.attributes(ds)["TYPE"])
|
||||
return HDF5PLOT_MAP_STR2TELEM[typestr]
|
||||
end
|
||||
|
||||
#Type parameter attributes:
|
||||
function _write_typeparam_attr(ds::Dataset, v::Length{T}) where T
|
||||
HDF5.attributes(ds)["TYPEPARAM"] = string(T) #Need to add units for Length
|
||||
end
|
||||
_read_typeparam_attr(ds::Dataset) = HDF5.read(HDF5.attributes(ds)["TYPEPARAM"])
|
||||
|
||||
function _write_length_attr(grp::Group, v::Vector) #of a vector
|
||||
HDF5.attributes(grp)["LENGTH"] = length(v)
|
||||
end
|
||||
_read_length_attr(::Type{Vector}, grp::Group) = HDF5.read(HDF5.attributes(grp)["LENGTH"])
|
||||
|
||||
function _write_size_attr(grp::Group, v::Array) #of an array
|
||||
HDF5.attributes(grp)["SIZE"] = [size(v)...]
|
||||
end
|
||||
_read_size_attr(::Type{Array}, grp::Group) = tuple(HDF5.read(HDF5.attributes(grp)["SIZE"])...)
|
||||
|
||||
|
||||
#==_write_typed(): Simple (leaf) datatypes. (Labels with type name.)
|
||||
===============================================================================#
|
||||
#= No: write out struct instead!
|
||||
function _write_typed(grp::Group, name::String, v::T) where T
|
||||
tstr = string(T)
|
||||
path = HDF5.name(grp) * "/" * name
|
||||
@info("Type not supported: $tstr\npath: $path")
|
||||
return
|
||||
end
|
||||
=#
|
||||
#Default behaviour: Assumes value is supported by HDF5 format
|
||||
function _write_typed(grp::Group, name::String, v::HDF5_SupportedTypes)
|
||||
grp[name] = v
|
||||
return #No need to _write_datatype_attr
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Nothing)
|
||||
grp[name] = "nothing" #Redundancy check/easier to read HDF5 file
|
||||
_write_datatype_attr(grp[name], Nothing)
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Symbol)
|
||||
grp[name] = String(v)
|
||||
_write_datatype_attr(grp[name], Symbol)
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Colorant)
|
||||
vstr = "#" * Colors.hex(v, :RRGGBBAA)
|
||||
grp[name] = vstr
|
||||
_write_datatype_attr(grp[name], Colorant)
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Extrema)
|
||||
grp[name] = [v.emin, v.emax] #More compact than writing struct
|
||||
_write_datatype_attr(grp[name], Extrema)
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Length)
|
||||
grp[name] = v.value
|
||||
_write_datatype_attr(grp[name], Length)
|
||||
_write_typeparam_attr(grp[name], v)
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::typeof(datetimeformatter))
|
||||
grp[name] = string(v) #Just write something that helps reader
|
||||
_write_datatype_attr(grp[name], typeof(datetimeformatter))
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Array{T}) where T<:Number #Default for arrays
|
||||
grp[name] = v
|
||||
return #No need to _write_datatype_attr
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::AbstractRange)
|
||||
_write_typed(grp, name, collect(v)) #For now
|
||||
end
|
||||
|
||||
|
||||
|
||||
#== Helper functions for writing complex data structures
|
||||
===============================================================================#
|
||||
|
||||
#Write an array using HDF5 hierarchy (when not using simple numeric eltype):
|
||||
function _write_harray(grp::Group, name::String, v::Array)
|
||||
sgrp = HDF5.create_group(grp, name)
|
||||
sz = size(v)
|
||||
lidx = LinearIndices(sz)
|
||||
|
||||
for iter in eachindex(v)
|
||||
coord = lidx[iter]
|
||||
elem = v[iter]
|
||||
idxstr = join(coord, "_")
|
||||
_write_typed(sgrp, "v$idxstr", elem)
|
||||
end
|
||||
|
||||
_write_size_attr(sgrp, v)
|
||||
end
|
||||
|
||||
#Write Dict without tagging with type:
|
||||
function _write(grp::Group, name::String, d::AbstractDict)
|
||||
sgrp = HDF5.create_group(grp, name)
|
||||
for (k, v) in d
|
||||
kstr = string(k)
|
||||
_write_typed(sgrp, kstr, v)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
#Write out arbitrary `struct`s:
|
||||
function _writestructgeneric(grp::Group, obj::T) where T
|
||||
for fname in fieldnames(T)
|
||||
v = getfield(obj, fname)
|
||||
_write_typed(grp, String(fname), v)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
#==_write_typed(): More complex structures. (Labels with type name.)
|
||||
===============================================================================#
|
||||
|
||||
#Catch-all (default behaviour for `struct`s):
|
||||
function _write_typed(grp::Group, name::String, v::T) where T
|
||||
#NOTE: need "name" parameter so that call signature is same with built-ins
|
||||
MT = _type_for_map(T)
|
||||
try #Check to see if type is supported
|
||||
typestr = HDF5PLOT_MAP_TELEM2STR[MT]
|
||||
catch
|
||||
@warn("HDF5Plots does not yet support structs of type `$MT`\n\n$grp")
|
||||
return
|
||||
end
|
||||
|
||||
#If attribute is supported and no writer is defined, then this should work:
|
||||
objgrp = HDF5.create_group(grp, name)
|
||||
_write_datatype_attr(objgrp, MT)
|
||||
_writestructgeneric(objgrp, v)
|
||||
end
|
||||
|
||||
function _write_typed(grp::Group, name::String, v::Array{T}) where T
|
||||
_write_harray(grp, name, v)
|
||||
_write_datatype_attr(grp[name], Array) #{Any}
|
||||
end
|
||||
|
||||
function _write_typed(grp::Group, name::String, v::Tuple, ::Type{ELT}) where ELT<: Number #Basic Tuple
|
||||
_write_typed(grp, name, [v...])
|
||||
_write_datatype_attr(grp[name], Tuple)
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, v::Tuple, ::Type) #CplxTuple
|
||||
_write_harray(grp, name, [v...])
|
||||
_write_datatype_attr(grp[name], CplxTuple)
|
||||
end
|
||||
_write_typed(grp::Group, name::String, v::Tuple) = _write_typed(grp, name, v, eltype(v))
|
||||
|
||||
function _write_typed(grp::Group, name::String, v::Dict)
|
||||
#=
|
||||
tstr = string(Dict)
|
||||
path = HDF5.name(grp) * "/" * name
|
||||
@info("Type not supported: $tstr\npath: $path")
|
||||
return
|
||||
=#
|
||||
#No support for structures with Dicts yet
|
||||
end
|
||||
function _write_typed(grp::Group, name::String, d::DefaultsDict) #Typically for plot attributes
|
||||
_write(grp, name, d)
|
||||
_write_datatype_attr(grp[name], DefaultsDict)
|
||||
end
|
||||
|
||||
function _write_typed(grp::Group, name::String, v::Axis)
|
||||
sgrp = HDF5.create_group(grp, name)
|
||||
#Ignore: sps::Vector{Subplot}
|
||||
_write_typed(sgrp, "plotattributes", v.plotattributes)
|
||||
_write_datatype_attr(sgrp, Axis)
|
||||
end
|
||||
|
||||
function _write_typed(grp::Group, name::String, v::Subplot)
|
||||
#Not for use in main "Plot.subplots[]" hierarchy. Just establishes reference with subplot_index.
|
||||
sgrp = HDF5.create_group(grp, name)
|
||||
_write_typed(sgrp, "index", v[:subplot_index])
|
||||
_write_datatype_attr(sgrp, Subplot)
|
||||
return
|
||||
end
|
||||
|
||||
function _write_typed(grp::Group, name::String, v::Plot)
|
||||
#Don't write plot references
|
||||
end
|
||||
|
||||
|
||||
#==_write(): Write out more complex structures
|
||||
NOTE: No need to write out type information (inferred from hierarchy)
|
||||
===============================================================================#
|
||||
|
||||
function _write(grp::Group, sp::Subplot{HDF5Backend})
|
||||
_write_typed(grp, "attr", sp.attr)
|
||||
|
||||
listgrp = HDF5.create_group(grp, "series_list")
|
||||
_write_length_attr(listgrp, sp.series_list)
|
||||
for (i, series) in enumerate(sp.series_list)
|
||||
#Just write .plotattributes part:
|
||||
_write(listgrp, "$i", series.plotattributes)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function _write(grp::Group, plt::Plot{HDF5Backend})
|
||||
_write_typed(grp, "attr", plt.attr)
|
||||
|
||||
listgrp = HDF5.create_group(grp, "subplots")
|
||||
_write_length_attr(listgrp, plt.subplots)
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
sgrp = HDF5.create_group(listgrp, "$i")
|
||||
_write(sgrp, sp)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString; name::String="_unnamed")
|
||||
HDF5.h5open(path, "w") do file
|
||||
HDF5.write_dataset(file, "VERSION_INFO", _get_Plots_versionstr())
|
||||
grp = HDF5.create_group(file, h5plotpath(name))
|
||||
_write(grp, plt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#== _read(): Read data, but not type information.
|
||||
===============================================================================#
|
||||
|
||||
#Types with built-in HDF5 support:
|
||||
_read(::Type{HDF5_AutoDetect}, ds::Dataset) = HDF5.read(ds)
|
||||
|
||||
function _read(::Type{Nothing}, ds::Dataset)
|
||||
nstr = "nothing"
|
||||
v = HDF5.read(ds)
|
||||
if nstr != v
|
||||
path = HDF5.name(ds)
|
||||
throw(Meta.ParseError("_read(::Nothing, ::Group): Read $v != $nstr:\n$path"))
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
_read(::Type{Symbol}, ds::Dataset) = Symbol(HDF5.read(ds))
|
||||
_read(::Type{Colorant}, ds::Dataset) = parse(Colorant, HDF5.read(ds))
|
||||
_read(::Type{Tuple}, ds::Dataset) = tuple(HDF5.read(ds)...)
|
||||
function _read(::Type{Extrema}, ds::Dataset)
|
||||
v = HDF5.read(ds)
|
||||
return Extrema(v[1], v[2])
|
||||
end
|
||||
function _read(::Type{Length}, ds::Dataset)
|
||||
TUNIT = Symbol(_read_typeparam_attr(ds))
|
||||
v = HDF5.read(ds)
|
||||
T = typeof(v)
|
||||
return Length{TUNIT,T}(v)
|
||||
end
|
||||
_read(::Type{typeof(datetimeformatter)}, ds::Dataset) = datetimeformatter
|
||||
|
||||
|
||||
#== Helper functions for reading in complex data structures
|
||||
===============================================================================#
|
||||
|
||||
#When type is unknown, _read_typed() figures it out:
|
||||
function _read_typed(grp::Group, name::String)
|
||||
ds = grp[name]
|
||||
t = _read_datatype_attr(ds)
|
||||
return _read(t, ds)
|
||||
end
|
||||
|
||||
#_readstructgeneric: Needs object values to be written out with _write_typed():
|
||||
function _readstructgeneric(::Type{T}, grp::Group) where T
|
||||
vlist = Array{Any}(nothing, fieldcount(T))
|
||||
for (i, fname) in enumerate(fieldnames(T))
|
||||
vlist[i] = _read_typed(grp, String(fname))
|
||||
end
|
||||
return T(vlist...)
|
||||
end
|
||||
|
||||
#Read KW from group:
|
||||
function _read(::Type{KW}, grp::Group)
|
||||
d = KW()
|
||||
gkeys = keys(grp)
|
||||
for k in gkeys
|
||||
try
|
||||
v = _read_typed(grp, k)
|
||||
d[Symbol(k)] = v
|
||||
catch e
|
||||
@show e
|
||||
@show grp
|
||||
@warn("Could not read field $k")
|
||||
end
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
|
||||
#== _read(): More complex structures.
|
||||
===============================================================================#
|
||||
|
||||
#Catch-all (default behaviour for `struct`s):
|
||||
_read(T::Type, grp::Group) = _readstructgeneric(T, grp)
|
||||
|
||||
function _read(::Type{Array}, grp::Group) #Array{Any}
|
||||
sz = _read_size_attr(Array, grp)
|
||||
if tuple(0) == sz; return []; end
|
||||
result = Array{Any}(undef, sz)
|
||||
lidx = LinearIndices(sz)
|
||||
|
||||
for iter in eachindex(result)
|
||||
coord = lidx[iter]
|
||||
idxstr = join(coord, "_")
|
||||
result[iter] = _read_typed(grp, "v$idxstr")
|
||||
end
|
||||
|
||||
#Hack: Implicitly make Julia detect element type.
|
||||
# (Should probably write it explicitly to file)
|
||||
result = [elem for elem in result] #Potentially make more specific
|
||||
return reshape(result, sz)
|
||||
end
|
||||
|
||||
_read(::Type{CplxTuple}, grp::Group) = tuple(_read(Array, grp)...)
|
||||
|
||||
function _read(::Type{GridLayout}, grp::Group)
|
||||
#parent = _read_typed(grp, "parent") #Can't use generic reader
|
||||
parent = RootLayout() #TODO: support parent???
|
||||
minpad = _read_typed(grp, "minpad")
|
||||
bbox = _read_typed(grp, "bbox")
|
||||
grid = _read_typed(grp, "grid")
|
||||
widths = _read_typed(grp, "widths")
|
||||
heights = _read_typed(grp, "heights")
|
||||
attr = KW() #TODO support attr: _read_typed(grp, "attr")
|
||||
|
||||
return GridLayout(parent, minpad, bbox, grid, widths, heights, attr)
|
||||
end
|
||||
#Defaults depends on context. So: user must constructs with defaults, then read.
|
||||
function _read(::Type{DefaultsDict}, grp::Group)
|
||||
#User should set DefaultsDict.defaults to one of:
|
||||
# _plot_defaults, _subplot_defaults, _axis_defaults, _series_defaults
|
||||
path = HDF5.name(ds)
|
||||
@warn("Cannot yet read DefaultsDict using _read_typed():\n $path\nCannot fully reconstruct plot.")
|
||||
end
|
||||
function _read(::Type{Axis}, grp::Group)
|
||||
#1st arg appears to be ref to subplots. Seems to work without it.
|
||||
return Axis([], DefaultsDict(_read(KW, grp["plotattributes"]), _axis_defaults))
|
||||
end
|
||||
function _read(::Type{Subplot}, grp::Group)
|
||||
#Not for use in main "Plot.subplots[]" hierarchy. Just establishes reference with subplot_index.
|
||||
idx = _read_typed(grp, "index")
|
||||
return HDF5PLOT_PLOTREF.ref.subplots[idx]
|
||||
end
|
||||
|
||||
|
||||
#== _read(): Main plot structures
|
||||
===============================================================================#
|
||||
|
||||
function _read(grp::Group, sp::Subplot)
|
||||
listgrp = HDF5.open_group(grp, "series_list")
|
||||
nseries = _read_length_attr(Vector, listgrp)
|
||||
|
||||
for i in 1:nseries
|
||||
sgrp = HDF5.open_group(listgrp, "$i")
|
||||
seriesinfo = _read(KW, sgrp)
|
||||
|
||||
plot!(sp, seriesinfo[:x], seriesinfo[:y]) #Add data & create data structures
|
||||
_hdf5_merge!(sp.series_list[end].plotattributes, seriesinfo)
|
||||
end
|
||||
|
||||
#Perform after adding series... otherwise values get overwritten:
|
||||
agrp = HDF5.open_group(grp, "attr")
|
||||
_hdf5_merge!(sp.attr, _read(KW, agrp))
|
||||
|
||||
return sp
|
||||
end
|
||||
|
||||
function _read_plot(grp::Group)
|
||||
listgrp = HDF5.open_group(grp, "subplots")
|
||||
n = _read_length_attr(Vector, listgrp)
|
||||
|
||||
#Construct new plot, +allocate subplots:
|
||||
plt = plot(layout=n)
|
||||
HDF5PLOT_PLOTREF.ref = plt #Used when reading "layout"
|
||||
|
||||
agrp = HDF5.open_group(grp, "attr")
|
||||
_hdf5_merge!(plt.attr, _read(KW, agrp))
|
||||
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
sgrp = HDF5.open_group(listgrp, "$i")
|
||||
_read(sgrp, sp)
|
||||
end
|
||||
|
||||
return plt
|
||||
end
|
||||
|
||||
function hdf5plot_read(path::AbstractString; name::String="_unnamed")
|
||||
HDF5.h5open(path, "r") do file
|
||||
grp = HDF5.open_group(file, h5plotpath("_unnamed"))
|
||||
return _read_plot(grp)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end #module _hdf5_implementation
|
||||
|
||||
|
||||
#==Implement Plots.jl backend interface for HDF5Backend
|
||||
===============================================================================#
|
||||
|
||||
is_marker_supported(::HDF5Backend, shape::Shape) = true
|
||||
|
||||
# Create the window/figure for this backend.
|
||||
function _create_backend_figure(plt::Plot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# # this is called early in the pipeline, use it to make the plot current or something
|
||||
# function _prepare_plot_object(plt::Plot{HDF5Backend})
|
||||
# end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set up the subplot within the backend object.
|
||||
function _initialize_subplot(plt::Plot{HDF5Backend}, sp::Subplot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Add one series to the underlying backend object.
|
||||
# Called once per series
|
||||
# NOTE: Seems to be called when user calls plot()... even if backend
|
||||
# plot, sp.o has not yet been constructed...
|
||||
function _series_added(plt::Plot{HDF5Backend}, series::Series)
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# When series data is added/changed, this callback can do dynamic updates to the backend object.
|
||||
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
|
||||
function _series_updated(plt::Plot{HDF5Backend}, series::Series)
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
# for the calcs
|
||||
function _before_layout_calcs(plt::Plot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
|
||||
function _update_plot_object(plt::Plot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Display/show the plot (open a GUI window, or browser page, for example).
|
||||
function _display(plt::Plot{HDF5Backend})
|
||||
msg = "HDF5 interface does not support `display()` function."
|
||||
msg *= "\nUse `Plots.hdf5plot_write(::String)` method to write to .HDF5 \"plot\" file instead."
|
||||
@warn(msg)
|
||||
return
|
||||
end
|
||||
|
||||
#==Interface actually required to use HDF5Backend
|
||||
===============================================================================#
|
||||
|
||||
hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString) = _hdf5_implementation.hdf5plot_write(plt, path)
|
||||
hdf5plot_write(path::AbstractString) = _hdf5_implementation.hdf5plot_write(current(), path)
|
||||
hdf5plot_read(path::AbstractString) = _hdf5_implementation.hdf5plot_read(path)
|
||||
|
||||
#Last line
|
||||
@@ -0,0 +1,534 @@
|
||||
|
||||
# https://github.com/ma-laforge/InspectDR.jl
|
||||
|
||||
#=TODO:
|
||||
Tweak scale factor for width & other sizes
|
||||
|
||||
Not supported by InspectDR:
|
||||
:foreground_color_grid
|
||||
:foreground_color_border
|
||||
:polar,
|
||||
|
||||
Add in functionality to Plots.jl:
|
||||
:aspect_ratio,
|
||||
=#
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
is_marker_supported(::InspectDRBackend, shape::Shape) = true
|
||||
|
||||
_inspectdr_to_pixels(bb::BoundingBox) =
|
||||
InspectDR.BoundingBox(to_pixels(left(bb)), to_pixels(right(bb)), to_pixels(top(bb)), to_pixels(bottom(bb)))
|
||||
|
||||
#Do we avoid Map to avoid possible pre-comile issues?
|
||||
function _inspectdr_mapglyph(s::Symbol)
|
||||
s == :rect && return :square
|
||||
return s
|
||||
end
|
||||
|
||||
function _inspectdr_mapglyph(s::Shape)
|
||||
x, y = coords(s)
|
||||
return InspectDR.GlyphPolyline(x, y)
|
||||
end
|
||||
|
||||
# py_marker(markers::AVec) = map(py_marker, markers)
|
||||
function _inspectdr_mapglyph(markers::AVec)
|
||||
@warn("Vectors of markers are currently unsupported in InspectDR.")
|
||||
_inspectdr_mapglyph(markers[1])
|
||||
end
|
||||
|
||||
_inspectdr_mapglyphsize(v::Real) = v
|
||||
function _inspectdr_mapglyphsize(v::Vector)
|
||||
@warn("Vectors of marker sizes are currently unsupported in InspectDR.")
|
||||
_inspectdr_mapglyphsize(v[1])
|
||||
end
|
||||
|
||||
_inspectdr_mapcolor(v::Colorant) = v
|
||||
function _inspectdr_mapcolor(g::PlotUtils.ColorGradient)
|
||||
@warn("Color gradients are currently unsupported in InspectDR.")
|
||||
#Pick middle color:
|
||||
_inspectdr_mapcolor(g.colors[div(1+end,2)])
|
||||
end
|
||||
function _inspectdr_mapcolor(v::AVec)
|
||||
@warn("Vectors of colors are currently unsupported in InspectDR.")
|
||||
#Pick middle color:
|
||||
_inspectdr_mapcolor(v[div(1+end,2)])
|
||||
end
|
||||
|
||||
#Hack: suggested point size does not seem adequate relative to plot size, for some reason.
|
||||
_inspectdr_mapptsize(v) = 1.5*v
|
||||
|
||||
function _inspectdr_add_annotations(plot, x, y, val)
|
||||
#What kind of annotation is this?
|
||||
end
|
||||
|
||||
#plot::InspectDR.Plot2D
|
||||
function _inspectdr_add_annotations(plot, x, y, val::PlotText)
|
||||
vmap = Dict{Symbol, Symbol}(:top=>:t, :bottom=>:b) #:vcenter
|
||||
hmap = Dict{Symbol, Symbol}(:left=>:l, :right=>:r) #:hcenter
|
||||
align = Symbol(get(vmap, val.font.valign, :c), get(hmap, val.font.halign, :c))
|
||||
fnt = InspectDR.Font(val.font.family, val.font.pointsize,
|
||||
color =_inspectdr_mapcolor(val.font.color)
|
||||
)
|
||||
ann = InspectDR.atext(val.str, x=x, y=y,
|
||||
font=fnt, angle=val.font.rotation, align=align
|
||||
)
|
||||
InspectDR.add(plot, ann)
|
||||
return
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_getaxisticks(ticks, gridlines, xfrm)
|
||||
TickCustom = InspectDR.TickCustom
|
||||
_xfrm(coord) = InspectDR.axis2aloc(Float64(coord), xfrm.spec) #Ensure Float64 - in case
|
||||
|
||||
ttype = ticksType(ticks)
|
||||
if ticks == :native
|
||||
#keep current
|
||||
elseif ttype == :ticks_and_labels
|
||||
pos = ticks[1]; labels = ticks[2]; nticks = length(ticks[1])
|
||||
newticks = TickCustom[TickCustom(_xfrm(pos[i]), labels[i]) for i in 1:nticks]
|
||||
gridlines = InspectDR.GridLinesCustom(gridlines)
|
||||
gridlines.major = newticks
|
||||
gridlines.minor = []
|
||||
gridlines.displayminor = false
|
||||
elseif ttype == :ticks
|
||||
nticks = length(ticks)
|
||||
gridlines.major = Float64[_xfrm(t) for t in ticks]
|
||||
gridlines.minor = []
|
||||
gridlines.displayminor = false
|
||||
elseif isnothing(ticks)
|
||||
gridlines.major = []
|
||||
gridlines.minor = []
|
||||
else #Assume ticks == :native
|
||||
#keep current
|
||||
end
|
||||
|
||||
return gridlines #keep current
|
||||
end
|
||||
|
||||
function _inspectdr_setticks(sp::Subplot, plot, strip, xaxis, yaxis)
|
||||
InputXfrm1D = InspectDR.InputXfrm1D
|
||||
_get_ticks(axis) = :native == axis[:ticks] ? (:native) : get_ticks(sp, axis)
|
||||
wantnative(ticks) = (:native == ticks)
|
||||
|
||||
xticks = _get_ticks(xaxis)
|
||||
yticks = _get_ticks(yaxis)
|
||||
|
||||
if wantnative(xticks) && wantnative(yticks)
|
||||
#Don't "eval" tick values
|
||||
return
|
||||
end
|
||||
|
||||
#TODO: Allow InspectDR to independently "eval" x or y ticks
|
||||
ext = InspectDR.getextents_aloc(plot, 1)
|
||||
grid = InspectDR._eval(strip.grid, plot.xscale, strip.yscale, ext)
|
||||
grid.xlines = _inspectdr_getaxisticks(xticks, grid.xlines, InputXfrm1D(plot.xscale))
|
||||
grid.ylines = _inspectdr_getaxisticks(yticks, grid.ylines, InputXfrm1D(strip.yscale))
|
||||
strip.grid = grid
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_getscale(s::Symbol, yaxis::Bool)
|
||||
#TODO: Support :asinh, :sqrt
|
||||
kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis
|
||||
if :log2 == s
|
||||
return InspectDR.AxisScale(:log2; kwargs...)
|
||||
elseif :log10 == s
|
||||
return InspectDR.AxisScale(:log10; kwargs...)
|
||||
elseif :ln == s
|
||||
return InspectDR.AxisScale(:ln; kwargs...)
|
||||
else #identity
|
||||
return InspectDR.AxisScale(:lin; kwargs...)
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
#Glyph used when plotting "Shape"s:
|
||||
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
|
||||
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
|
||||
)
|
||||
|
||||
mutable struct InspecDRPlotRef
|
||||
mplot::Union{Nothing, InspectDR.Multiplot}
|
||||
gui::Union{Nothing, InspectDR.GtkPlot}
|
||||
end
|
||||
|
||||
_inspectdr_getmplot(::Any) = nothing
|
||||
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
|
||||
|
||||
_inspectdr_getgui(::Any) = nothing
|
||||
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
|
||||
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
|
||||
push!(_initialized_backends, :inspectdr)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Create the window/figure for this backend.
|
||||
function _create_backend_figure(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
#:overwrite_figure: want to reuse current figure
|
||||
if plt[:overwrite_figure] && mplot !== nothing
|
||||
mplot.subplots = [] #Reset
|
||||
if gplot !== nothing #Ensure still references current plot
|
||||
gplot.src = mplot
|
||||
end
|
||||
else #want new one:
|
||||
mplot = InspectDR.Multiplot()
|
||||
gplot = nothing #Will be created later
|
||||
end
|
||||
|
||||
#break link with old subplots
|
||||
for sp in plt.subplots
|
||||
sp.o = nothing
|
||||
end
|
||||
|
||||
return InspecDRPlotRef(mplot, gplot)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# # this is called early in the pipeline, use it to make the plot current or something
|
||||
# function _prepare_plot_object(plt::Plot{InspectDRBackend})
|
||||
# end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set up the subplot within the backend object.
|
||||
function _initialize_subplot(plt::Plot{InspectDRBackend}, sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
#Don't do anything without a "subplot" object: Will process later.
|
||||
if nothing == plot; return; end
|
||||
plot.data = []
|
||||
plot.userannot = [] #Clear old markers/text annotation/polyline "annotation"
|
||||
return plot
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Add one series to the underlying backend object.
|
||||
# Called once per series
|
||||
# NOTE: Seems to be called when user calls plot()... even if backend
|
||||
# plot, sp.o has not yet been constructed...
|
||||
function _series_added(plt::Plot{InspectDRBackend}, series::Series)
|
||||
st = series[:seriestype]
|
||||
sp = series[:subplot]
|
||||
plot = sp.o
|
||||
clims = get_clims(sp, 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
|
||||
x, y = if st == :straightline
|
||||
straightline_data(series)
|
||||
else
|
||||
_vectorize(series[:x]), _vectorize(series[:y])
|
||||
end
|
||||
|
||||
#No support for polar grid... but can still perform polar transformation:
|
||||
if ispolar(sp)
|
||||
Θ = x; r = y
|
||||
x = r.*cos.(Θ); y = r.*sin.(Θ)
|
||||
end
|
||||
|
||||
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
|
||||
nx = length(x); ny = length(y)
|
||||
if nx < ny
|
||||
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
elseif ny > nx
|
||||
series[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
end
|
||||
|
||||
#= TODO: Eventually support
|
||||
series[:fillcolor] #I think this is fill under line
|
||||
zorder = series[:series_plotindex]
|
||||
|
||||
For st in :shape:
|
||||
zorder = series[:series_plotindex],
|
||||
=#
|
||||
|
||||
if st in (:shape,)
|
||||
x, y = shape_data(series)
|
||||
nmax = 0
|
||||
for (i,rng) in enumerate(iter_segments(x, y))
|
||||
nmax = i
|
||||
if length(rng) > 1
|
||||
linewidth = series[:linewidth]
|
||||
c = plot_color(get_linecolor(series), get_linealpha(series))
|
||||
linecolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
c = plot_color(get_fillcolor(series), get_fillalpha(series))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
line = InspectDR.line(
|
||||
style=:solid, width=linewidth, color=linecolor
|
||||
)
|
||||
apline = InspectDR.PolylineAnnotation(
|
||||
x[rng], y[rng], line=line, fillcolor=fillcolor
|
||||
)
|
||||
InspectDR.add(plot, apline)
|
||||
end
|
||||
end
|
||||
|
||||
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]
|
||||
c = plot_color(get_linecolor(series), get_linealpha(series))
|
||||
linecolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
c = plot_color(get_fillcolor(series), get_fillalpha(series))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
wfrm = InspectDR.add(plot, Float64[], Float64[], id=series[:label])
|
||||
wfrm.line = InspectDR.line(
|
||||
style=:none, width=linewidth, #linewidth affects glyph
|
||||
)
|
||||
wfrm.glyph = InspectDR.glyph(
|
||||
shape = INSPECTDR_GLYPH_SHAPE, size = 8,
|
||||
color = linecolor, fillcolor = fillcolor
|
||||
)
|
||||
end
|
||||
elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost)
|
||||
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
|
||||
linewidth = series[:linewidth]
|
||||
#More efficient & allows some support for markerstrokewidth:
|
||||
_style = (0==linewidth ? :none : series[:linestyle])
|
||||
wfrm = InspectDR.add(plot, x, y, id=series[:label])
|
||||
wfrm.line = InspectDR.line(
|
||||
style = _style,
|
||||
width = series[:linewidth],
|
||||
color = plot_color(get_linecolor(series), get_linealpha(series)),
|
||||
)
|
||||
#InspectDR does not control markerstrokewidth independently.
|
||||
if :none == _style
|
||||
#Use this property only if no line is displayed:
|
||||
wfrm.line.width = series[:markerstrokewidth]
|
||||
end
|
||||
wfrm.glyph = InspectDR.glyph(
|
||||
shape = _inspectdr_mapglyph(series[:markershape]),
|
||||
size = _inspectdr_mapglyphsize(series[:markersize]),
|
||||
color = _inspectdr_mapcolor(plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series))),
|
||||
fillcolor = _inspectdr_mapcolor(plot_color(get_markercolor(series, clims), get_markeralpha(series))),
|
||||
)
|
||||
end
|
||||
|
||||
# this is all we need to add the series_annotations text
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, x, y)
|
||||
_inspectdr_add_annotations(plot, xi, yi, PlotText(str, fnt))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# When series data is added/changed, this callback can do dynamic updates to the backend object.
|
||||
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
|
||||
function _series_updated(plt::Plot{InspectDRBackend}, series::Series)
|
||||
#Nothing to do
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
strip = plot.strips[1] #Only 1 strip supported with Plots.jl
|
||||
|
||||
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
|
||||
xgrid_show = xaxis[:grid]
|
||||
ygrid_show = yaxis[:grid]
|
||||
|
||||
strip.grid = InspectDR.GridRect(
|
||||
vmajor=xgrid_show, # vminor=xgrid_show,
|
||||
hmajor=ygrid_show, # hminor=ygrid_show,
|
||||
)
|
||||
|
||||
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
|
||||
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
|
||||
xmin, xmax = axis_limits(sp, :x)
|
||||
ymin, ymax = axis_limits(sp, :y)
|
||||
if ispolar(sp)
|
||||
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
|
||||
rmax = NaNMath.max(abs(ymin), abs(ymax))
|
||||
xmin, xmax = -rmax, rmax
|
||||
ymin, ymax = -rmax, rmax
|
||||
end
|
||||
plot.xext_full = InspectDR.PExtents1D(xmin, xmax)
|
||||
strip.yext_full = InspectDR.PExtents1D(ymin, ymax)
|
||||
#Set current extents = full extents (needed for _eval(strip.grid,...))
|
||||
plot.xext = plot.xext_full
|
||||
strip.yext = strip.yext_full
|
||||
_inspectdr_setticks(sp, plot, strip, xaxis, yaxis)
|
||||
|
||||
a = plot.annotation
|
||||
a.title = sp[:title]
|
||||
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
|
||||
|
||||
l = plot.layout
|
||||
#IMPORTANT: Don't forget to actually register changes
|
||||
#(TODO: need to find a better way to set layout properties)
|
||||
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l[:frame_canvas] = l[:frame_canvas] #register changes
|
||||
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l[:frame_data] = l[:frame_data] #register changes
|
||||
|
||||
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l[:frame_data] = l[:frame_data] #register changes
|
||||
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[:guidefontfamily],
|
||||
_inspectdr_mapptsize(xaxis[:guidefontsize]),
|
||||
color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
|
||||
)
|
||||
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[:legendfontfamily],
|
||||
_inspectdr_mapptsize(sp[:legendfontsize]),
|
||||
color = _inspectdr_mapcolor(sp[:legendfontcolor])
|
||||
)
|
||||
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
l[:frame_legend] = l[:frame_legend] #register changes
|
||||
end
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
# for the calcs
|
||||
function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
|
||||
mplot.title = plt[:plot_title]
|
||||
if "" == mplot.title
|
||||
#Don't use window_title... probably not what you want.
|
||||
#mplot.title = plt[:window_title]
|
||||
end
|
||||
|
||||
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
|
||||
mplot.layout[:frame] = mplot.layout[:frame] #register changes
|
||||
resize!(mplot.subplots, length(plt.subplots))
|
||||
nsubplots = length(plt.subplots)
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
if !isassigned(mplot.subplots, i)
|
||||
mplot.subplots[i] = InspectDR.Plot2D()
|
||||
end
|
||||
sp.o = mplot.subplots[i]
|
||||
plot = sp.o
|
||||
_initialize_subplot(plt, sp)
|
||||
_inspectdr_setupsubplot(sp)
|
||||
|
||||
# add the annotations
|
||||
for ann in sp[:annotations]
|
||||
_inspectdr_add_annotations(plot, ann...)
|
||||
end
|
||||
end
|
||||
|
||||
#Do not yet support absolute plot positionning.
|
||||
#Just try to make things look more-or less ok:
|
||||
if nsubplots <= 1
|
||||
mplot.layout[:ncolumns] = 1
|
||||
elseif nsubplots <= 4
|
||||
mplot.layout[:ncolumns] = 2
|
||||
elseif nsubplots <= 6
|
||||
mplot.layout[:ncolumns] = 3
|
||||
elseif nsubplots <= 12
|
||||
mplot.layout[:ncolumns] = 4
|
||||
else
|
||||
mplot.layout[:ncolumns] = 5
|
||||
end
|
||||
|
||||
for series in plt.series_list
|
||||
_series_added(plt, series)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
|
||||
#Computing plotbounds with 0-BoundingBox returns required padding:
|
||||
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
|
||||
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
|
||||
#TODO: possibly zero-out items not in use??
|
||||
|
||||
# add in the user-specified margin to InspectDR padding:
|
||||
leftpad = abs(bb.xmin)*px + sp[:left_margin]
|
||||
toppad = abs(bb.ymin)*px + sp[:top_margin]
|
||||
rightpad = abs(bb.xmax)*px + sp[:right_margin]
|
||||
bottompad = abs(bb.ymax)*px + sp[:bottom_margin]
|
||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
|
||||
function _update_plot_object(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
graphbb = _inspectdr_to_pixels(plotarea(sp))
|
||||
plot = mplot.subplots[i]
|
||||
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
|
||||
end
|
||||
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
if nothing == gplot; return; end
|
||||
|
||||
gplot.src = mplot #Ensure still references current plot
|
||||
InspectDR.refresh(gplot)
|
||||
return
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
_inspectdr_show(io::IO, mime::MIME, ::Nothing, w, h) =
|
||||
throw(ErrorException("Cannot show(::IO, ...) plot - not yet generated"))
|
||||
function _inspectdr_show(io::IO, mime::MIME, mplot, w, h)
|
||||
InspectDR._show(io, mime, mplot, Float64(w), Float64(h))
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME{Symbol("image/png")}, plt::Plot{InspectDRBackend})
|
||||
dpi = plt[:dpi] # TODO: support
|
||||
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
|
||||
end
|
||||
for (mime, fmt) in (
|
||||
"image/svg+xml" => "svg",
|
||||
"application/eps" => "eps",
|
||||
"image/eps" => "eps",
|
||||
# "application/postscript" => "ps", # TODO: support once Cairo supports PSSurface
|
||||
"application/pdf" => "pdf",
|
||||
)
|
||||
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{InspectDRBackend})
|
||||
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Display/show the plot (open a GUI window, or browser page, for example).
|
||||
function _display(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
if nothing == gplot
|
||||
gplot = display(InspectDR.GtkDisplay(), mplot)
|
||||
else
|
||||
#redundant... Plots.jl will call _update_plot_object:
|
||||
#InspectDR.refresh(gplot)
|
||||
end
|
||||
plt.o = InspecDRPlotRef(mplot, gplot)
|
||||
return gplot
|
||||
end
|
||||
@@ -0,0 +1,971 @@
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
is_subplot_supported(::PlotlyBackend) = true
|
||||
# is_string_supported(::PlotlyBackend) = true
|
||||
function _plotly_framestyle(style::Symbol)
|
||||
if style in (:box, :axes, :zerolines, :grid, :none)
|
||||
return style
|
||||
else
|
||||
default_style = get((semi = :box, origin = :zerolines), style, :axes)
|
||||
@warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
|
||||
default_style
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
using UUIDs
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function labelfunc(scale::Symbol, backend::PlotlyBackend)
|
||||
texfunc = labelfunc_tex(scale)
|
||||
function (x)
|
||||
tex_x = texfunc(x)
|
||||
sup_x = replace( tex_x, r"\^{(.*)}"=>s"<sup>\1</sup>" )
|
||||
# replace dash with \minus (U+2212)
|
||||
replace(sup_x, "-" => "−")
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_font(font::Font, color = font.color)
|
||||
KW(
|
||||
:family => font.family,
|
||||
:size => round(Int, font.pointsize*1.4),
|
||||
:color => rgba_string(color),
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
|
||||
KW(
|
||||
:text => val,
|
||||
:xref => xref,
|
||||
:x => x,
|
||||
:yref => yref,
|
||||
:y => y,
|
||||
:showarrow => false,
|
||||
)
|
||||
end
|
||||
|
||||
function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper")
|
||||
merge(plotly_annotation_dict(x, y, ptxt.str; xref=xref, yref=yref), KW(
|
||||
:font => plotly_font(ptxt.font),
|
||||
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
|
||||
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
|
||||
:rotation => -ptxt.font.rotation,
|
||||
))
|
||||
end
|
||||
|
||||
# function get_annotation_dict_for_arrow(plotattributes::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
|
||||
# xdiff = xyprev[1] - xy[1]
|
||||
# ydiff = xyprev[2] - xy[2]
|
||||
# dist = sqrt(xdiff^2 + ydiff^2)
|
||||
# KW(
|
||||
# :showarrow => true,
|
||||
# :x => xy[1],
|
||||
# :y => xy[2],
|
||||
# # :ax => xyprev[1] - xy[1],
|
||||
# # :ay => xy[2] - xyprev[2],
|
||||
# # :ax => 0,
|
||||
# # :ay => -40,
|
||||
# :ax => 10xdiff / dist,
|
||||
# :ay => -10ydiff / dist,
|
||||
# :arrowcolor => rgba_string(plotattributes[:linecolor]),
|
||||
# :xref => "x",
|
||||
# :yref => "y",
|
||||
# :arrowsize => 10a.headwidth,
|
||||
# # :arrowwidth => a.headlength,
|
||||
# :arrowwidth => 0.1,
|
||||
# )
|
||||
# end
|
||||
|
||||
function plotly_scale(scale::Symbol)
|
||||
if scale == :log10
|
||||
"log"
|
||||
else
|
||||
"-"
|
||||
end
|
||||
end
|
||||
|
||||
function shrink_by(lo, sz, ratio)
|
||||
amt = 0.5 * (1.0 - ratio) * sz
|
||||
lo + amt, sz - 2amt
|
||||
end
|
||||
|
||||
function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
|
||||
aspect_ratio = get_aspect_ratio(sp)
|
||||
if aspect_ratio != :none
|
||||
if aspect_ratio == :equal
|
||||
aspect_ratio = 1.0
|
||||
end
|
||||
xmin,xmax = axis_limits(sp, :x)
|
||||
ymin,ymax = axis_limits(sp, :y)
|
||||
want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio
|
||||
parea_ratio = width(plotarea) / height(plotarea)
|
||||
if want_ratio > parea_ratio
|
||||
# need to shrink y
|
||||
ratio = parea_ratio / want_ratio
|
||||
pcts[2], pcts[4] = shrink_by(pcts[2], pcts[4], ratio)
|
||||
elseif want_ratio < parea_ratio
|
||||
# need to shrink x
|
||||
ratio = want_ratio / parea_ratio
|
||||
pcts[1], pcts[3] = shrink_by(pcts[1], pcts[3], ratio)
|
||||
end
|
||||
pcts
|
||||
end
|
||||
pcts
|
||||
end
|
||||
|
||||
|
||||
# this method gets the start/end in percentage of the canvas for this axis direction
|
||||
function plotly_domain(sp::Subplot)
|
||||
figw, figh = sp.plt[:size]
|
||||
pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px)
|
||||
pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts)
|
||||
x_domain = [pcts[1], pcts[1] + pcts[3]]
|
||||
y_domain = [pcts[2], pcts[2] + pcts[4]]
|
||||
return x_domain, y_domain
|
||||
end
|
||||
|
||||
|
||||
function plotly_axis(axis, sp, anchor = nothing, domain = nothing)
|
||||
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 => 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 anchor !== nothing
|
||||
ax[:anchor] = anchor
|
||||
end
|
||||
if domain !== nothing
|
||||
ax[:domain] = domain
|
||||
end
|
||||
|
||||
ax[:tickangle] = -axis[:rotation]
|
||||
ax[:type] = plotly_scale(axis[:scale])
|
||||
lims = axis_limits(sp, letter)
|
||||
|
||||
if axis[:ticks] != :native || axis[:lims] != :auto
|
||||
ax[:range] = map(RecipesPipeline.scale_func(axis[:scale]), lims)
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, :none, false))
|
||||
ax[:titlefont] = plotly_font(guidefont(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])
|
||||
|
||||
# ticks
|
||||
if axis[:ticks] != :native
|
||||
ticks = get_ticks(sp, axis)
|
||||
ttype = ticksType(ticks)
|
||||
if ttype == :ticks
|
||||
ax[:tickmode] = "array"
|
||||
ax[:tickvals] = ticks
|
||||
elseif ttype == :ticks_and_labels
|
||||
ax[:tickmode] = "array"
|
||||
ax[:tickvals], ax[:ticktext] = ticks
|
||||
end
|
||||
end
|
||||
else
|
||||
ax[:showticklabels] = false
|
||||
ax[:showgrid] = false
|
||||
end
|
||||
|
||||
# flip
|
||||
if axis[:flip]
|
||||
ax[:range] = reverse(ax[:range])
|
||||
end
|
||||
|
||||
ax
|
||||
end
|
||||
|
||||
function plotly_polaraxis(sp::Subplot, axis::Axis)
|
||||
ax = KW(
|
||||
:visible => axis[:showaxis],
|
||||
:showline => axis[:grid],
|
||||
)
|
||||
|
||||
if axis[:letter] == :x
|
||||
ax[:range] = rad2deg.(axis_limits(sp, :x))
|
||||
else
|
||||
ax[:range] = axis_limits(sp, :y)
|
||||
ax[:orientation] = -90
|
||||
end
|
||||
|
||||
ax
|
||||
end
|
||||
|
||||
function plotly_layout(plt::Plot)
|
||||
plotattributes_out = KW()
|
||||
|
||||
w, h = plt[:size]
|
||||
plotattributes_out[:width], plotattributes_out[:height] = w, h
|
||||
plotattributes_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
|
||||
plotattributes_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
|
||||
|
||||
plotattributes_out[:annotations] = KW[]
|
||||
|
||||
multiple_subplots = length(plt.subplots) > 1
|
||||
|
||||
for sp in plt.subplots
|
||||
spidx = multiple_subplots ? sp[:subplot_index] : ""
|
||||
x_idx, y_idx = multiple_subplots ? plotly_link_indicies(plt, sp) : ("", "")
|
||||
# add an annotation for the title... positioned horizontally relative to plotarea,
|
||||
# but vertically just below the top of the subplot bounding box
|
||||
if sp[:title] != ""
|
||||
bb = plotarea(sp)
|
||||
tpos = sp[:titlelocation]
|
||||
xmm = if tpos == :left
|
||||
left(bb)
|
||||
elseif tpos == :right
|
||||
right(bb)
|
||||
else
|
||||
0.5 * (left(bb) + right(bb))
|
||||
end
|
||||
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
|
||||
title_font = font(titlefont(sp), :top)
|
||||
push!(plotattributes_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
|
||||
end
|
||||
|
||||
plotattributes_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
|
||||
|
||||
# set to supported framestyle
|
||||
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
|
||||
|
||||
if ispolar(sp)
|
||||
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis])
|
||||
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis])
|
||||
else
|
||||
x_domain, y_domain = plotly_domain(sp)
|
||||
if RecipesPipeline.is3d(sp)
|
||||
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
|
||||
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
|
||||
plotattributes_out[Symbol(:scene, spidx)] = KW(
|
||||
:domain => KW(:x => x_domain, :y => y_domain),
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
plotattributes_out[Symbol("xaxis$(x_idx)")] =
|
||||
plotly_axis(sp[:xaxis], sp, string("y", y_idx) , x_domain)
|
||||
# don't allow yaxis to be reupdated/reanchored in a linked subplot
|
||||
if spidx == y_idx
|
||||
plotattributes_out[Symbol("yaxis$(y_idx)")] =
|
||||
plotly_axis(sp[:yaxis], sp, string("x", x_idx), y_domain)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# legend
|
||||
plotly_add_legend!(plotattributes_out, sp)
|
||||
|
||||
# annotations
|
||||
for ann in sp[:annotations]
|
||||
append!(plotattributes_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
|
||||
end
|
||||
# series_annotations
|
||||
for series in series_list(sp)
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
|
||||
push!(plotattributes_out[:annotations], plotly_annotation_dict(
|
||||
xi,
|
||||
yi,
|
||||
PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# # arrows
|
||||
# for sargs in seriesargs
|
||||
# a = sargs[:arrow]
|
||||
# if sargs[:seriestype] in (:path, :line) && typeof(a) <: Arrow
|
||||
# add_arrows(sargs[:x], sargs[:y]) do xyprev, xy
|
||||
# push!(plotattributes_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a))
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
if ispolar(sp)
|
||||
plotattributes_out[:direction] = "counterclockwise"
|
||||
end
|
||||
|
||||
plotattributes_out
|
||||
end
|
||||
|
||||
# turn off hover if nothing's using it
|
||||
if all(series -> series.plotattributes[:hover] in (false,:none), plt.series_list)
|
||||
plotattributes_out[:hovermode] = "none"
|
||||
end
|
||||
|
||||
plotattributes_out = recursive_merge(plotattributes_out, plt.attr[:extra_plot_kwargs])
|
||||
end
|
||||
|
||||
|
||||
function plotly_add_legend!(plotattributes_out::KW, sp::Subplot)
|
||||
plotattributes_out[:showlegend] = sp[:legend] != :none
|
||||
legend_position = plotly_legend_pos(sp[:legend])
|
||||
if sp[:legend] != :none
|
||||
plotattributes_out[:legend] = KW(
|
||||
:bgcolor => rgba_string(sp[:background_color_legend]),
|
||||
:bordercolor => rgba_string(sp[:foreground_color_legend]),
|
||||
:borderwidth => 1,
|
||||
:traceorder => "normal",
|
||||
:xanchor => legend_position.xanchor,
|
||||
:yanchor => legend_position.yanchor,
|
||||
:font => plotly_font(legendfont(sp)),
|
||||
:tracegroupgap => 0,
|
||||
:x => legend_position.coords[1],
|
||||
:y => legend_position.coords[2],
|
||||
:title => KW(
|
||||
:text => sp[:legendtitle] === nothing ? "" : string(sp[:legendtitle]),
|
||||
:font => plotly_font(legendtitlefont(sp)),
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_legend_pos(pos::Symbol)
|
||||
xleft = 0.07
|
||||
ybot = 0.07
|
||||
ytop = 1.0
|
||||
xcenter = 0.55
|
||||
ycenter = 0.52
|
||||
center = 0.5
|
||||
youtertop = 1.1
|
||||
youterbot = -0.15
|
||||
xouterright = 1.05
|
||||
xouterleft = -0.15
|
||||
plotly_legend_position_mapping = (
|
||||
right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"),
|
||||
left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"),
|
||||
top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"),
|
||||
bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"),
|
||||
bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"),
|
||||
bottomright = (coords = [1.0, ybot], xanchor = "right", yanchor = "bottom"),
|
||||
topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"),
|
||||
topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"),
|
||||
outertop =(coords = [center, youtertop ], xanchor = "upper", yanchor = "middle"),
|
||||
outerbottom =(coords = [center, youterbot], xanchor = "lower", yanchor = "middle"),
|
||||
outerleft =(coords = [xouterleft, center], xanchor = "left", yanchor = "top"),
|
||||
outerright =(coords = [xouterright, center], xanchor = "right", yanchor = "top"),
|
||||
outertopleft =(coords = [xouterleft, ytop], xanchor = "upper", yanchor = "left"),
|
||||
outertopright = (coords = [xouterright, ytop], xanchor = "upper", yanchor = "right"),
|
||||
outerbottomleft =(coords = [xouterleft, ybot], xanchor = "lower", yanchor = "left"),
|
||||
outerbottomright =(coords = [xouterright, ybot], xanchor = "lower", yanchor = "right"),
|
||||
default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto")
|
||||
)
|
||||
|
||||
legend_position = get(plotly_legend_position_mapping, pos, plotly_legend_position_mapping.default)
|
||||
end
|
||||
|
||||
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = (coords=v, xanchor="left", yanchor="top")
|
||||
|
||||
|
||||
function plotly_layout_json(plt::Plot)
|
||||
JSON.json(plotly_layout(plt), 4)
|
||||
end
|
||||
|
||||
|
||||
plotly_colorscale(cg::ColorGradient, α = nothing) =
|
||||
[[v, rgba_string(plot_color(cg.colors[v], α))] for v in cg.values]
|
||||
function plotly_colorscale(c::AbstractVector{<:Colorant}, α = nothing)
|
||||
if length(c) == 1
|
||||
return [
|
||||
[0.0, rgba_string(plot_color(c[1], α))],
|
||||
[1.0, rgba_string(plot_color(c[1], α))],
|
||||
]
|
||||
else
|
||||
vals = range(0.0, stop = 1.0, length = length(c))
|
||||
return [[vals[i], rgba_string(plot_color(c[i], α))] for i in eachindex(c)]
|
||||
end
|
||||
end
|
||||
function plotly_colorscale(cg::PlotUtils.CategoricalColorGradient, α = nothing)
|
||||
n = length(cg)
|
||||
cinds = repeat(1:n, inner = 2)
|
||||
vinds = vcat((i:(i + 1) for i in 1:n)...)
|
||||
return [
|
||||
[cg.values[vinds[i]], rgba_string(plot_color(color_list(cg)[cinds[i]], α))]
|
||||
for i in eachindex(cinds)
|
||||
]
|
||||
end
|
||||
plotly_colorscale(c, α = nothing) = plotly_colorscale(_as_gradient(c), α)
|
||||
|
||||
|
||||
get_plotly_marker(k, def) = get(
|
||||
(
|
||||
rect = "square",
|
||||
xcross = "x",
|
||||
x = "x",
|
||||
utriangle = "triangle-up",
|
||||
dtriangle = "triangle-down",
|
||||
star5 = "star-triangle-up",
|
||||
vline = "line-ns",
|
||||
hline = "line-ew",
|
||||
),
|
||||
k,
|
||||
def,
|
||||
)
|
||||
|
||||
# find indicies of axes to which the supblot links to
|
||||
function plotly_link_indicies(plt::Plot, sp::Subplot)
|
||||
if plt[:link] in (:x, :y, :both)
|
||||
x_idx = sp[:xaxis].sps[1][:subplot_index]
|
||||
y_idx = sp[:yaxis].sps[1][:subplot_index]
|
||||
else
|
||||
x_idx = y_idx = sp[:subplot_index]
|
||||
end
|
||||
x_idx, y_idx
|
||||
end
|
||||
|
||||
|
||||
# the Shape contructor will automatically close the shape. since we need it closed,
|
||||
# we split by NaNs and then construct/destruct the shapes to get the closed coords
|
||||
function plotly_close_shapes(x, y)
|
||||
xs, ys = nansplit(x), nansplit(y)
|
||||
for i=eachindex(xs)
|
||||
shape = Shape(xs[i], ys[i])
|
||||
xs[i], ys[i] = coords(shape)
|
||||
end
|
||||
nanvcat(xs), nanvcat(ys)
|
||||
end
|
||||
|
||||
function plotly_data(series::Series, letter::Symbol, data)
|
||||
axis = series[:subplot][Symbol(letter, :axis)]
|
||||
|
||||
data = if axis[:ticks] == :native && data !== nothing
|
||||
plotly_native_data(axis, data)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe, :mesh3d)
|
||||
handle_surface(data)
|
||||
else
|
||||
plotly_data(data)
|
||||
end
|
||||
end
|
||||
plotly_data(v) = v !== nothing ? collect(v) : v
|
||||
plotly_data(v::AbstractArray) = v
|
||||
plotly_data(surf::Surface) = surf.surf
|
||||
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
|
||||
|
||||
function plotly_native_data(axis::Axis, data::AbstractArray)
|
||||
if !isempty(axis[:discrete_values])
|
||||
construct_categorical_data(data, axis)
|
||||
elseif axis[:formatter] in (datetimeformatter, dateformatter, timeformatter)
|
||||
plotly_convert_to_datetime(data, axis[:formatter])
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
plotly_native_data(axis::Axis, a::Surface) = Surface(plotly_native_data(axis, a.surf))
|
||||
|
||||
function plotly_convert_to_datetime(x::AbstractArray, formatter::Function)
|
||||
if formatter == datetimeformatter
|
||||
map(xi -> replace(formatter(xi), "T" => " "), x)
|
||||
elseif formatter == dateformatter
|
||||
map(xi -> string(formatter(xi), " 00:00:00"), x)
|
||||
elseif formatter == timeformatter
|
||||
map(xi -> string(Dates.Date(Dates.now()), " ", formatter(xi)), x)
|
||||
else
|
||||
error("Invalid DateTime formatter. Expected Plots.datetime/date/time formatter but got $formatter")
|
||||
end
|
||||
end
|
||||
#ensures that a gradient is called if a single color is supplied where a gradient is needed (e.g. if a series recipe defines marker_z)
|
||||
as_gradient(grad::ColorGradient, α) = grad
|
||||
as_gradient(grad, α) = cgrad(alpha = α)
|
||||
|
||||
# get a dictionary representing the series params (plotattributes is the Plots-dict, plotattributes_out is the Plotly-dict)
|
||||
function plotly_series(plt::Plot, series::Series)
|
||||
st = series[:seriestype]
|
||||
|
||||
sp = series[:subplot]
|
||||
clims = get_clims(sp, series)
|
||||
|
||||
if st == :shape
|
||||
return plotly_series_shapes(plt, series, clims)
|
||||
end
|
||||
|
||||
plotattributes_out = KW()
|
||||
|
||||
# these are the axes that the series should be mapped to
|
||||
if RecipesPipeline.is3d(sp)
|
||||
spidx = length(plt.subplots) > 1 ? sp[:subplot_index] : ""
|
||||
plotattributes_out[:xaxis] = "x$spidx"
|
||||
plotattributes_out[:yaxis] = "y$spidx"
|
||||
plotattributes_out[:zaxis] = "z$spidx"
|
||||
plotattributes_out[:scene] = "scene$spidx"
|
||||
else
|
||||
x_idx, y_idx = length(plt.subplots) > 1 ? plotly_link_indicies(plt, sp) : ("", "")
|
||||
plotattributes_out[:xaxis] = "x$(x_idx)"
|
||||
plotattributes_out[:yaxis] = "y$(y_idx)"
|
||||
end
|
||||
plotattributes_out[:showlegend] = should_add_to_legend(series)
|
||||
|
||||
if st == :straightline
|
||||
x, y = straightline_data(series, 100)
|
||||
z = series[:z]
|
||||
else
|
||||
x, y, z = series[:x], series[:y], series[:z]
|
||||
end
|
||||
|
||||
x, y, z = (plotly_data(series, letter, data)
|
||||
for (letter, data) in zip((:x, :y, :z), (x, y, z))
|
||||
)
|
||||
|
||||
plotattributes_out[:name] = series[:label]
|
||||
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || series[:markershape] != :none
|
||||
hasline = st in (:path, :path3d, :straightline)
|
||||
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
|
||||
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
|
||||
|
||||
plotattributes_out[:colorbar] = KW(:title => sp[:colorbar_title])
|
||||
|
||||
if is_2tuple(clims)
|
||||
plotattributes_out[:zmin], plotattributes_out[:zmax] = clims
|
||||
end
|
||||
|
||||
# set the "type"
|
||||
if st in (:path, :scatter, :scattergl, :straightline, :path3d, :scatter3d)
|
||||
return plotly_series_segments(series, plotattributes_out, x, y, z, clims)
|
||||
|
||||
elseif st == :heatmap
|
||||
x = heatmap_edges(x, sp[:xaxis][:scale])
|
||||
y = heatmap_edges(y, sp[:yaxis][:scale])
|
||||
plotattributes_out[:type] = "heatmap"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
|
||||
elseif st == :contour
|
||||
filled = isfilledcontour(series)
|
||||
plotattributes_out[:type] = "contour"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
plotattributes_out[:ncontours] = series[:levels] + 2
|
||||
plotattributes_out[:contours] = KW(:coloring => filled ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series)
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
plotattributes_out[:type] = "surface"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
if st == :wireframe
|
||||
plotattributes_out[:hidesurface] = true
|
||||
wirelines = KW(
|
||||
:show => true,
|
||||
:color => rgba_string(plot_color(series[:linecolor], series[:linealpha])),
|
||||
:highlightwidth => series[:linewidth],
|
||||
)
|
||||
plotattributes_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
|
||||
plotattributes_out[:showscale] = false
|
||||
else
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
plotattributes_out[:opacity] = series[:fillalpha]
|
||||
if series[:fill_z] !== nothing
|
||||
plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z])
|
||||
end
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
end
|
||||
elseif st == :mesh3d
|
||||
plotattributes_out[:type] = "mesh3d"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
|
||||
if series[:connections] !== nothing
|
||||
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
|
||||
i,j,k = series[:connections]
|
||||
if !(length(i) == length(j) == length(k))
|
||||
throw(ArgumentError("Argument connections must consist of equally sized arrays."))
|
||||
end
|
||||
plotattributes_out[:i] = i
|
||||
plotattributes_out[:j] = j
|
||||
plotattributes_out[:k] = k
|
||||
else
|
||||
throw(ArgumentError("Argument connections has to be a tuple of three arrays."))
|
||||
end
|
||||
end
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
plotattributes_out[:color] = rgba_string(plot_color(series[:fillcolor], series[:fillalpha]))
|
||||
plotattributes_out[:opacity] = series[:fillalpha]
|
||||
if series[:fill_z] !== nothing
|
||||
plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z])
|
||||
end
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
else
|
||||
@warn("Plotly: seriestype $st isn't supported.")
|
||||
return KW()
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
inds = eachindex(x)
|
||||
plotattributes_out[:marker] = KW(
|
||||
:symbol => get_plotly_marker(series[:markershape], string(series[:markershape])),
|
||||
# :opacity => series[:markeralpha],
|
||||
:size => 2 * _cycle(series[:markersize], inds),
|
||||
:color => rgba_string.(plot_color.(get_markercolor.(series, inds), get_markeralpha.(series, inds))),
|
||||
:line => KW(
|
||||
:color => rgba_string.(plot_color.(get_markerstrokecolor.(series, inds), get_markerstrokealpha.(series, inds))),
|
||||
:width => _cycle(series[:markerstrokewidth], inds),
|
||||
),
|
||||
)
|
||||
end
|
||||
|
||||
plotly_polar!(plotattributes_out, series)
|
||||
plotly_hover!(plotattributes_out, series[:hover])
|
||||
|
||||
return [plotattributes_out]
|
||||
end
|
||||
|
||||
function plotly_series_shapes(plt::Plot, series::Series, clims)
|
||||
segments = iter_segments(series)
|
||||
plotattributes_outs = Vector{KW}(undef, length(segments))
|
||||
|
||||
# TODO: create a plotattributes_out for each polygon
|
||||
# x, y = series[:x], series[:y]
|
||||
|
||||
# these are the axes that the series should be mapped to
|
||||
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
|
||||
plotattributes_base = KW(
|
||||
:xaxis => "x$(x_idx)",
|
||||
:yaxis => "y$(y_idx)",
|
||||
:name => series[:label],
|
||||
:legendgroup => series[:label],
|
||||
)
|
||||
|
||||
x, y = (plotly_data(series, letter, data)
|
||||
for (letter, data) in zip((:x, :y), shape_data(series, 100))
|
||||
)
|
||||
|
||||
for (i,rng) in enumerate(segments)
|
||||
length(rng) < 2 && continue
|
||||
|
||||
# to draw polygons, we actually draw lines with fill
|
||||
plotattributes_out = merge(plotattributes_base, KW(
|
||||
:type => "scatter",
|
||||
:mode => "lines",
|
||||
:x => vcat(x[rng], x[rng[1]]),
|
||||
:y => vcat(y[rng], y[rng[1]]),
|
||||
:fill => "tozeroy",
|
||||
:fillcolor => rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))),
|
||||
))
|
||||
if series[:markerstrokewidth] > 0
|
||||
plotattributes_out[:line] = KW(
|
||||
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
|
||||
:width => get_linewidth(series, i),
|
||||
:dash => string(get_linestyle(series, i)),
|
||||
)
|
||||
end
|
||||
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
plotly_polar!(plotattributes_out, series)
|
||||
plotly_hover!(plotattributes_out, _cycle(series[:hover], i))
|
||||
plotattributes_outs[i] = plotattributes_out
|
||||
end
|
||||
if series[:fill_z] !== nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
|
||||
elseif series[:line_z] !== nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
|
||||
elseif series[:marker_z] !== nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
|
||||
end
|
||||
plotattributes_outs
|
||||
end
|
||||
|
||||
function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z, clims)
|
||||
st = series[:seriestype]
|
||||
sp = series[:subplot]
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || series[:markershape] != :none
|
||||
hasline = st in (:path, :path3d, :straightline)
|
||||
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
|
||||
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
|
||||
|
||||
segments = iter_segments(series, st)
|
||||
plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1 ) * length(segments))
|
||||
|
||||
needs_scatter_fix = !isscatter && hasmarker && !any(isnan,y) && length(segments) > 1
|
||||
|
||||
for (i,rng) in enumerate(segments)
|
||||
plotattributes_out = deepcopy(plotattributes_base)
|
||||
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
plotattributes_out[:legendgroup] = series[:label]
|
||||
|
||||
# set the type
|
||||
if st in (:path, :scatter, :scattergl, :straightline)
|
||||
plotattributes_out[:type] = st==:scattergl ? "scattergl" : "scatter"
|
||||
plotattributes_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
|
||||
plotattributes_out[:fill] = "tozeroy"
|
||||
plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
|
||||
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
|
||||
plotattributes_out[:fill] = "tonexty"
|
||||
plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
|
||||
elseif !(series[:fillrange] in (false, nothing))
|
||||
@warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
|
||||
end
|
||||
plotattributes_out[:x], plotattributes_out[:y] = x[rng], y[rng]
|
||||
|
||||
elseif st in (:path3d, :scatter3d)
|
||||
plotattributes_out[:type] = "scatter3d"
|
||||
plotattributes_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x[rng], y[rng], z[rng]
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
mcolor = rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i)))
|
||||
lcolor = rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i)))
|
||||
plotattributes_out[:marker] = KW(
|
||||
:symbol => get_plotly_marker(_cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
|
||||
# :opacity => needs_scatter_fix ? [1, 0] : 1,
|
||||
:size => 2 * _cycle(series[:markersize], i),
|
||||
:color => needs_scatter_fix ? [mcolor, "rgba(0, 0, 0, 0.000)"] : mcolor,
|
||||
:line => KW(
|
||||
:color => needs_scatter_fix ? [lcolor, "rgba(0, 0, 0, 0.000)"] : lcolor,
|
||||
:width => _cycle(series[:markerstrokewidth], i),
|
||||
),
|
||||
)
|
||||
end
|
||||
|
||||
# add "line"
|
||||
if hasline
|
||||
plotattributes_out[:line] = KW(
|
||||
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
|
||||
:width => get_linewidth(series, i),
|
||||
:shape => if st == :steppre
|
||||
"vh"
|
||||
elseif st == :steppost
|
||||
"hv"
|
||||
else
|
||||
"linear"
|
||||
end,
|
||||
:dash => string(get_linestyle(series, i)),
|
||||
)
|
||||
end
|
||||
|
||||
plotly_polar!(plotattributes_out, series)
|
||||
plotly_hover!(plotattributes_out, _cycle(series[:hover], rng))
|
||||
|
||||
if hasfillrange
|
||||
# if hasfillrange is true, return two dictionaries (one for original
|
||||
# series, one for series being filled to) instead of one
|
||||
plotattributes_out_fillrange = deepcopy(plotattributes_out)
|
||||
plotattributes_out_fillrange[:showlegend] = false
|
||||
# if fillrange is provided as real or tuple of real, expand to array
|
||||
if typeof(series[:fillrange]) <: Real
|
||||
series[:fillrange] = fill(series[:fillrange], length(rng))
|
||||
elseif typeof(series[:fillrange]) <: Tuple
|
||||
f1 = typeof(series[:fillrange][1]) <: Real ? fill(series[:fillrange][1], length(rng)) : series[:fillrange][1][rng]
|
||||
f2 = typeof(series[:fillrange][2]) <: Real ? fill(series[:fillrange][2], length(rng)) : series[:fillrange][2][rng]
|
||||
series[:fillrange] = (f1, f2)
|
||||
end
|
||||
if isa(series[:fillrange], AbstractVector)
|
||||
plotattributes_out_fillrange[:y] = series[:fillrange][rng]
|
||||
delete!(plotattributes_out_fillrange, :fill)
|
||||
delete!(plotattributes_out_fillrange, :fillcolor)
|
||||
else
|
||||
# if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange
|
||||
# is the series that will do the filling
|
||||
plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], series[:fillrange])
|
||||
plotattributes_out_fillrange[:line][:width] = 0
|
||||
delete!(plotattributes_out, :fill)
|
||||
delete!(plotattributes_out, :fillcolor)
|
||||
end
|
||||
|
||||
plotattributes_outs[(2 * i - 1):(2 * i)] = [plotattributes_out_fillrange, plotattributes_out]
|
||||
else
|
||||
plotattributes_outs[i] = plotattributes_out
|
||||
end
|
||||
end
|
||||
|
||||
if series[:line_z] !== nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
|
||||
elseif series[:fill_z] !== nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
|
||||
elseif series[:marker_z] !== nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
|
||||
end
|
||||
|
||||
plotattributes_outs
|
||||
end
|
||||
|
||||
function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symbol)
|
||||
plotattributes_out = deepcopy(plotattributes_base)
|
||||
cmin, cmax = get_clims(series[:subplot])
|
||||
plotattributes_out[:showlegend] = false
|
||||
plotattributes_out[:type] = RecipesPipeline.is3d(series) ? :scatter3d : :scatter
|
||||
plotattributes_out[:hoverinfo] = :none
|
||||
plotattributes_out[:mode] = :markers
|
||||
plotattributes_out[:x], plotattributes_out[:y] = [series[:x][1]], [series[:y][1]]
|
||||
if RecipesPipeline.is3d(series)
|
||||
plotattributes_out[:z] = [series[:z][1]]
|
||||
end
|
||||
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
|
||||
plotattributes_out[:marker] = KW(
|
||||
:size => 1e-10,
|
||||
:opacity => 1e-10,
|
||||
:color => [0.5],
|
||||
:cmin => cmin,
|
||||
:cmax => cmax,
|
||||
:colorscale => plotly_colorscale(series[Symbol("$(sym)color")], 1),
|
||||
:showscale => hascolorbar(series[:subplot]),
|
||||
)
|
||||
return plotattributes_out
|
||||
end
|
||||
|
||||
|
||||
function plotly_polar!(plotattributes_out::KW, series::Series)
|
||||
# convert polar plots x/y to theta/radius
|
||||
if ispolar(series[:subplot])
|
||||
theta, r = pop!(plotattributes_out, :x), pop!(plotattributes_out, :y)
|
||||
plotattributes_out[:t] = rad2deg.(theta)
|
||||
plotattributes_out[:r] = r
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_hover!(plotattributes_out::KW, hover)
|
||||
# hover text
|
||||
if hover === nothing || all(in([:none, false]), hover)
|
||||
plotattributes_out[:hoverinfo] = "none"
|
||||
elseif any(!isnothing, hover)
|
||||
plotattributes_out[:hoverinfo] = "text"
|
||||
plotattributes_out[:text] = hover
|
||||
end
|
||||
end
|
||||
|
||||
# get a list of dictionaries, each representing the series params
|
||||
function plotly_series(plt::Plot)
|
||||
slist = []
|
||||
for series in plt.series_list
|
||||
append!(slist, plotly_series(plt, series))
|
||||
end
|
||||
slist
|
||||
end
|
||||
|
||||
# get json string for a list of dictionaries, each representing the series params
|
||||
plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt), 4)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
html_head(plt::Plot{PlotlyBackend}) = plotly_html_head(plt)
|
||||
html_body(plt::Plot{PlotlyBackend}) = plotly_html_body(plt)
|
||||
|
||||
function plotly_html_head(plt::Plot)
|
||||
plotly =
|
||||
use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/$(_plotly_min_js_filename)"
|
||||
|
||||
include_mathjax = get(plt[:extra_plot_kwargs], :include_mathjax, "")
|
||||
mathjax_file = include_mathjax != "cdn" ? ("file://" * include_mathjax) : "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML"
|
||||
mathjax_head = include_mathjax == "" ? "" : "<script src=\"$mathjax_file\"></script>\n\t\t"
|
||||
|
||||
if isijulia()
|
||||
mathjax_head
|
||||
else
|
||||
"$mathjax_head<script src=$(repr(plotly))></script>"
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_html_body(plt, style = nothing)
|
||||
if style === nothing
|
||||
w, h = plt[:size]
|
||||
style = "width:$(w)px;height:$(h)px;"
|
||||
end
|
||||
|
||||
requirejs_prefix = ""
|
||||
requirejs_suffix = ""
|
||||
if isijulia()
|
||||
# require.js adds .js automatically
|
||||
plotly_no_ext =
|
||||
use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/$(_plotly_min_js_filename)"
|
||||
plotly_no_ext = plotly_no_ext[1:end-3]
|
||||
|
||||
requirejs_prefix = """
|
||||
requirejs.config({
|
||||
paths: {
|
||||
Plotly: '$(plotly_no_ext)'
|
||||
}
|
||||
});
|
||||
require(['Plotly'], function (Plotly) {
|
||||
"""
|
||||
requirejs_suffix = "});"
|
||||
end
|
||||
|
||||
uuid = UUIDs.uuid4()
|
||||
html = """
|
||||
<div id=\"$(uuid)\" style=\"$(style)\"></div>
|
||||
<script>
|
||||
$(requirejs_prefix)
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
|
||||
$(requirejs_suffix)
|
||||
</script>
|
||||
"""
|
||||
html
|
||||
end
|
||||
|
||||
function js_body(plt::Plot, uuid)
|
||||
js = """
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
|
||||
"""
|
||||
end
|
||||
|
||||
function plotly_show_js(io::IO, plot::Plot)
|
||||
data = []
|
||||
for series in plot.series_list
|
||||
append!(data, plotly_series(plot, series))
|
||||
end
|
||||
layout = plotly_layout(plot)
|
||||
JSON.print(io, Dict(:data => data, :layout => layout))
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot{PlotlyBackend}) = true
|
||||
|
||||
function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{PlotlyBackend})
|
||||
plotly_show_js(io, plot)
|
||||
end
|
||||
|
||||
|
||||
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
|
||||
write(io, standalone_html(plt))
|
||||
end
|
||||
|
||||
|
||||
function _display(plt::Plot{PlotlyBackend})
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
function plotlybase_syncplot(plt::Plot)
|
||||
plt.o = PlotlyBase.Plot()
|
||||
traces = PlotlyBase.GenericTrace[]
|
||||
for series_dict in plotly_series(plt)
|
||||
plotly_type = pop!(series_dict, :type)
|
||||
push!(traces, PlotlyBase.GenericTrace(plotly_type; series_dict...))
|
||||
end
|
||||
PlotlyBase.addtraces!(plt.o, traces...)
|
||||
layout = plotly_layout(plt)
|
||||
w, h = plt[:size]
|
||||
PlotlyBase.relayout!(plt.o, layout, width = w, height = h)
|
||||
return plt.o
|
||||
end
|
||||
|
||||
for (mime, fmt) in (
|
||||
"application/pdf" => "pdf",
|
||||
"image/png" => "png",
|
||||
"image/svg+xml" => "svg",
|
||||
"image/eps" => "eps",
|
||||
)
|
||||
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyBackend}) =
|
||||
PlotlyBase.savefig(io, plotlybase_syncplot(plt), format = $fmt)
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
# https://github.com/sglyon/PlotlyJS.jl
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
function plotlyjs_syncplot(plt::Plot{PlotlyJSBackend})
|
||||
plt[:overwrite_figure] && closeall()
|
||||
plt.o = PlotlyJS.plot()
|
||||
traces = PlotlyJS.GenericTrace[]
|
||||
for series_dict in plotly_series(plt)
|
||||
plotly_type = pop!(series_dict, :type)
|
||||
push!(traces, PlotlyJS.GenericTrace(plotly_type; series_dict...))
|
||||
end
|
||||
PlotlyJS.addtraces!(plt.o, traces...)
|
||||
layout = plotly_layout(plt)
|
||||
w, h = plt[:size]
|
||||
PlotlyJS.relayout!(plt.o, layout, width = w, height = h)
|
||||
return plt.o
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
for (mime, fmt) in (
|
||||
"application/pdf" => "pdf",
|
||||
"image/png" => "png",
|
||||
"image/svg+xml" => "svg",
|
||||
"image/eps" => "eps",
|
||||
)
|
||||
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt)
|
||||
end
|
||||
|
||||
# Use the Plotly implementation for json and html:
|
||||
_show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) = plotly_show_js(io, plt)
|
||||
|
||||
html_head(plt::Plot{PlotlyJSBackend}) = plotly_html_head(plt)
|
||||
html_body(plt::Plot{PlotlyJSBackend}) = plotly_html_body(plt)
|
||||
|
||||
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = write(io, standalone_html(plt))
|
||||
|
||||
_display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt))
|
||||
|
||||
function PlotlyJS.WebIO.render(plt::Plot{PlotlyJSBackend})
|
||||
plt_html = sprint(show, MIME("text/html"), plt)
|
||||
return PlotlyJS.WebIO.render(PlotlyJS.WebIO.dom"div"(innerHTML=plt_html))
|
||||
end
|
||||
|
||||
function closeall(::PlotlyJSBackend)
|
||||
if !isplotnull() && isa(current().o, PlotlyJS.SyncPlot)
|
||||
close(current().o)
|
||||
end
|
||||
end
|
||||
|
||||
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot{PlotlyJSBackend}) = true
|
||||
@@ -1,70 +0,0 @@
|
||||
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
immutable QwtPackage <: PlottingPackage end
|
||||
|
||||
qwt!() = plotter!(:qwt)
|
||||
|
||||
# -------------------------------
|
||||
|
||||
function adjustQwtKeywords(iscreating::Bool; kw...)
|
||||
d = Dict(kw)
|
||||
d[:heatmap_n] = d[:nbins]
|
||||
|
||||
if d[:linetype] == :hexbin
|
||||
d[:linetype] = :heatmap
|
||||
elseif d[:linetype] == :dots
|
||||
d[:linetype] = :none
|
||||
d[:marker] = :hexagon
|
||||
elseif !iscreating && d[:linetype] == :bar
|
||||
return barHack(; kw...)
|
||||
elseif !iscreating && d[:linetype] == :hist
|
||||
return barHack(; histogramHack(; kw...)...)
|
||||
end
|
||||
d
|
||||
end
|
||||
|
||||
function plot(pkg::QwtPackage; kw...)
|
||||
kw = adjustQwtKeywords(true; kw...)
|
||||
o = Qwt.plot(zeros(0,0); kw..., show=false)
|
||||
plt = Plot(o, pkg, 0, kw, Dict[])
|
||||
plt
|
||||
end
|
||||
|
||||
function plot!(::QwtPackage, plt::Plot; kw...)
|
||||
kw = adjustQwtKeywords(false; kw...)
|
||||
Qwt.oplot(plt.o; kw...)
|
||||
push!(plt.seriesargs, kw)
|
||||
plt
|
||||
end
|
||||
|
||||
function Base.display(::QwtPackage, plt::Plot)
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.showwidget(plt.o)
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
savepng(::QwtPackage, plt::PlottingObject, fn::String, args...) = Qwt.savepng(plt.o, fn)
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# create the underlying object (each backend will do this differently)
|
||||
function buildSubplotObject!(::QwtPackage, subplt::Subplot)
|
||||
i = 0
|
||||
rows = []
|
||||
for rowcnt in subplt.layout.rowcounts
|
||||
push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
|
||||
i += rowcnt
|
||||
end
|
||||
subplt.o = Qwt.vsplitter(rows...)
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::QwtPackage, subplt::Subplot)
|
||||
for plt in subplt.plts
|
||||
Qwt.refresh(plt.o)
|
||||
end
|
||||
Qwt.showwidget(subplt.o)
|
||||
end
|
||||
|
||||
@@ -1,161 +1,180 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
immutable UnicodePlotsPackage <: PlottingPackage end
|
||||
|
||||
unicodeplots!() = plotter!(:unicodeplots)
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
|
||||
|
||||
# -------------------------------
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function expandLimits!(lims, x)
|
||||
e1, e2 = extrema(x)
|
||||
lims[1] = min(lims[1], e1)
|
||||
lims[2] = max(lims[2], e2)
|
||||
nothing
|
||||
function _canvas_map()
|
||||
(
|
||||
braille = UnicodePlots.BrailleCanvas,
|
||||
ascii = UnicodePlots.AsciiCanvas,
|
||||
block = UnicodePlots.BlockCanvas,
|
||||
dot = UnicodePlots.DotCanvas,
|
||||
density = UnicodePlots.DensityCanvas,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
|
||||
function rebuildUnicodePlot!(plt::Plot)
|
||||
function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
plt.o = []
|
||||
|
||||
# figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
|
||||
sargs = plt.seriesargs
|
||||
xlim = [Inf, -Inf]
|
||||
ylim = [Inf, -Inf]
|
||||
for d in sargs
|
||||
expandLimits!(xlim, d[:x])
|
||||
expandLimits!(ylim, d[:y])
|
||||
end
|
||||
x = Float64[xlim[1]]
|
||||
y = Float64[ylim[1]]
|
||||
for sp in plt.subplots
|
||||
xaxis = sp[:xaxis]
|
||||
yaxis = sp[:yaxis]
|
||||
xlim = axis_limits(sp, :x)
|
||||
ylim = axis_limits(sp, :y)
|
||||
|
||||
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
|
||||
iargs = plt.initargs
|
||||
width, height = iargs[:size]
|
||||
o = UnicodePlots.createPlotWindow(x, y; width = width,
|
||||
height = height,
|
||||
title = iargs[:title],
|
||||
# labels = iargs[:legend],
|
||||
xlim = xlim,
|
||||
ylim = ylim)
|
||||
# make vectors
|
||||
xlim = [xlim[1], xlim[2]]
|
||||
ylim = [ylim[1], ylim[2]]
|
||||
|
||||
# set the axis labels
|
||||
UnicodePlots.xlabel!(o, iargs[:xlabel])
|
||||
UnicodePlots.ylabel!(o, iargs[:ylabel])
|
||||
# we set x/y to have a single point, since we need to create the plot with some data.
|
||||
# since this point is at the bottom left corner of the plot, it shouldn't actually be shown
|
||||
x = Float64[xlim[1]]
|
||||
y = Float64[ylim[1]]
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
for d in sargs
|
||||
addUnicodeSeries!(o, d, iargs[:legend])
|
||||
end
|
||||
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
|
||||
ct = _canvas_type[]
|
||||
canvas_type = if ct == :auto
|
||||
isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
|
||||
else
|
||||
_canvas_map()[ct]
|
||||
end
|
||||
|
||||
# save the object
|
||||
plt.o = o
|
||||
# special handling for spy
|
||||
if length(sp.series_list) == 1
|
||||
series = sp.series_list[1]
|
||||
if series[:seriestype] == :spy
|
||||
push!(plt.o, UnicodePlots.spy(
|
||||
series[:z].surf,
|
||||
width = width,
|
||||
height = height,
|
||||
title = sp[:title],
|
||||
canvas = canvas_type
|
||||
))
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
# # make it a bar canvas if plotting bar
|
||||
# if any(series -> series[:seriestype] == :bar, series_list(sp))
|
||||
# canvas_type = UnicodePlots.BarplotGraphics
|
||||
# end
|
||||
|
||||
o = UnicodePlots.Plot(x, y, canvas_type;
|
||||
width = width,
|
||||
height = height,
|
||||
title = sp[:title],
|
||||
xlim = xlim,
|
||||
ylim = ylim,
|
||||
border = isijulia() ? :ascii : :solid
|
||||
)
|
||||
|
||||
# set the axis labels
|
||||
UnicodePlots.xlabel!(o, xaxis[:guide])
|
||||
UnicodePlots.ylabel!(o, yaxis[:guide])
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
for series in series_list(sp)
|
||||
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
|
||||
end
|
||||
|
||||
# save the object
|
||||
push!(plt.o, o)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# add a single series
|
||||
function addUnicodeSeries!(o, d::Dict, addlegend::Bool)
|
||||
function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim)
|
||||
# get the function, or special handling for step/bar/hist
|
||||
st = plotattributes[:seriestype]
|
||||
if st == :histogram2d
|
||||
UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
|
||||
return
|
||||
end
|
||||
|
||||
# get the function, or special handling for step/bar/hist
|
||||
lt = d[:linetype]
|
||||
stepstyle = :post
|
||||
if lt == :line
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif lt == :dots || d[:marker] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
elseif lt == :step
|
||||
func = UnicodePlots.stairs!
|
||||
elseif lt == :stepinverted
|
||||
func = UnicodePlots.stairs!
|
||||
stepstyle = :pre
|
||||
else
|
||||
error("Linestyle $lt not supported by UnicodePlots")
|
||||
end
|
||||
|
||||
# get the series data and label
|
||||
x, y = [collect(float(d[s])) for s in (:x, :y)]
|
||||
label = addlegend ? d[:label] : ""
|
||||
if st in (:path, :straightline)
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif st == :scatter || plotattributes[:markershape] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
# elseif st == :bar
|
||||
# func = UnicodePlots.barplot!
|
||||
elseif st == :shape
|
||||
func = UnicodePlots.lineplot!
|
||||
else
|
||||
error("Linestyle $st not supported by UnicodePlots")
|
||||
end
|
||||
|
||||
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
|
||||
color = d[:color] in UnicodePlots.autoColors ? d[:color] : :auto
|
||||
# get the series data and label
|
||||
x, y = if st == :straightline
|
||||
straightline_data(plotattributes)
|
||||
elseif st == :shape
|
||||
shape_data(plotattributes)
|
||||
else
|
||||
[collect(float(plotattributes[s])) for s in (:x, :y)]
|
||||
end
|
||||
label = addlegend ? plotattributes[:label] : ""
|
||||
|
||||
# add the series
|
||||
func(o, x, y; color = color, name = label, style = stepstyle)
|
||||
end
|
||||
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
|
||||
color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto
|
||||
|
||||
|
||||
# -------------------------------
|
||||
|
||||
|
||||
function plot(pkg::UnicodePlotsPackage; kw...)
|
||||
plt = Plot(nothing, pkg, 0, Dict(kw), Dict[])
|
||||
|
||||
# do we want to give a new default size?
|
||||
if !haskey(plt.initargs, :size) || plt.initargs[:size] == PLOT_DEFAULTS[:size]
|
||||
plt.initargs[:size] = (60,20)
|
||||
end
|
||||
|
||||
plt
|
||||
end
|
||||
|
||||
function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
if d[:linetype] in (:sticks, :bar)
|
||||
d = barHack(; d...)
|
||||
elseif d[:linetype] == :hist
|
||||
d = barHack(; histogramHack(; d...)...)
|
||||
end
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
function Base.display(::UnicodePlotsPackage, plt::Plot)
|
||||
rebuildUnicodePlot!(plt)
|
||||
show(plt.o)
|
||||
# add the series
|
||||
x, y = RecipesPipeline.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
|
||||
func(o, x, y; color = color, name = label)
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
function savepng(::UnicodePlotsPackage, plt::PlottingObject, fn::String, args...)
|
||||
# since this is such a hack, it's only callable using `png`... should error during normal `show`
|
||||
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
|
||||
fn = addExtension(fn, "png")
|
||||
|
||||
# make some whitespace and show the plot
|
||||
println("\n\n\n\n\n\n")
|
||||
display(plt)
|
||||
# make some whitespace and show the plot
|
||||
println("\n\n\n\n\n\n")
|
||||
gui(plt)
|
||||
|
||||
@osx_only begin
|
||||
# BEGIN HACK
|
||||
# @osx_only begin
|
||||
@static if Sys.isapple()
|
||||
# BEGIN HACK
|
||||
|
||||
# wait while the plot gets drawn
|
||||
sleep(0.5)
|
||||
# wait while the plot gets drawn
|
||||
sleep(0.5)
|
||||
|
||||
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
|
||||
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
|
||||
run(`screencapture -R50,600,700,420 $fn`)
|
||||
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
|
||||
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
|
||||
run(`screencapture -R50,600,700,420 $fn`)
|
||||
|
||||
# # some other attempts:
|
||||
# run(`screencapture -w $fn`)
|
||||
# using PyCall
|
||||
# @pyimport pyscreenshot as pss
|
||||
# END HACK (phew)
|
||||
return
|
||||
end
|
||||
|
||||
# END HACK (phew)
|
||||
return
|
||||
end
|
||||
|
||||
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
|
||||
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# we don't do very much for subplots... just stack them vertically
|
||||
|
||||
function buildSubplotObject!(::UnicodePlotsPackage, subplt::Subplot)
|
||||
nothing
|
||||
function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
|
||||
w, h = plt[:size]
|
||||
plt.attr[:color_palette] = [RGB(0,0,0)]
|
||||
rebuildUnicodePlot!(plt, div(w, 10), div(h, 20))
|
||||
end
|
||||
|
||||
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
|
||||
unicodeplots_rebuild(plt)
|
||||
foreach(x -> show(io, x), plt.o)
|
||||
nothing
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::UnicodePlotsPackage, subplt::Subplot)
|
||||
for plt in subplt.plts
|
||||
display(UnicodePlotsPackage(), plt)
|
||||
end
|
||||
function _display(plt::Plot{UnicodePlotsBackend})
|
||||
unicodeplots_rebuild(plt)
|
||||
map(show, plt.o)
|
||||
nothing
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
# NOTE: backend should implement `html_body` and `html_head`
|
||||
|
||||
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
|
||||
|
||||
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
|
||||
"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>$title</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
$(html_head(plt))
|
||||
</head>
|
||||
<body>
|
||||
$(html_body(plt))
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
end
|
||||
|
||||
function open_browser_window(filename::AbstractString)
|
||||
@static if Sys.isapple()
|
||||
return run(`open $(filename)`)
|
||||
end
|
||||
@static if Sys.islinux() || Sys.isbsd() # Sys.isbsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
|
||||
return run(`xdg-open $(filename)`)
|
||||
end
|
||||
@static if Sys.iswindows()
|
||||
return run(`$(ENV["COMSPEC"]) /c start "" "$(filename)"`)
|
||||
end
|
||||
@warn("Unknown OS... cannot open browser window.")
|
||||
end
|
||||
|
||||
function write_temp_html(plt::AbstractPlot)
|
||||
html = standalone_html(plt; title = plt.attr[:window_title])
|
||||
filename = string(tempname(), ".html")
|
||||
output = open(filename, "w")
|
||||
write(output, html)
|
||||
close(output)
|
||||
filename
|
||||
end
|
||||
|
||||
function standalone_html_window(plt::AbstractPlot)
|
||||
old = use_local_dependencies[] # save state to restore afterwards
|
||||
# if we open a browser ourself, we can host local files, so
|
||||
# when we have a local plotly downloaded this is the way to go!
|
||||
use_local_dependencies[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
|
||||
filename = write_temp_html(plt)
|
||||
open_browser_window(filename)
|
||||
# restore for other backends
|
||||
use_local_dependencies[] = old
|
||||
end
|
||||
|
||||
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
|
||||
function html_to_png(html_fn, png_fn, w, h)
|
||||
run(`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`)
|
||||
end
|
||||
|
||||
function show_png_from_html(io::IO, plt::AbstractPlot)
|
||||
# write html to a temporary file
|
||||
html_fn = write_temp_html(plt)
|
||||
|
||||
# convert that html file to a temporary png file using wkhtmltoimage
|
||||
png_fn = tempname() * ".png"
|
||||
w, h = plt.attr[:size]
|
||||
html_to_png(html_fn, png_fn, w, h)
|
||||
|
||||
# now read that file data into io
|
||||
pngdata = readall(png_fn)
|
||||
write(io, pngdata)
|
||||
end
|
||||
@@ -0,0 +1,760 @@
|
||||
const P2 = GeometryBasics.Point2{Float64}
|
||||
const P3 = GeometryBasics.Point3{Float64}
|
||||
|
||||
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
|
||||
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
|
||||
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
|
||||
struct Shape
|
||||
x::Vector{Float64}
|
||||
y::Vector{Float64}
|
||||
# function Shape(x::AVec, y::AVec)
|
||||
# # if x[1] != x[end] || y[1] != y[end]
|
||||
# # new(vcat(x, x[1]), vcat(y, y[1]))
|
||||
# # else
|
||||
# new(x, y)
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
"""
|
||||
Shape(x, y)
|
||||
Shape(vertices)
|
||||
|
||||
Construct a polygon to be plotted
|
||||
"""
|
||||
Shape(verts::AVec) = Shape(RecipesPipeline.unzip(verts)...)
|
||||
Shape(s::Shape) = deepcopy(s)
|
||||
|
||||
get_xs(shape::Shape) = shape.x
|
||||
get_ys(shape::Shape) = shape.y
|
||||
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
|
||||
|
||||
function coords(shapes::AVec{Shape})
|
||||
length(shapes) == 0 && return zeros(0), zeros(0)
|
||||
xs = map(get_xs, shapes)
|
||||
ys = map(get_ys, shapes)
|
||||
x, y = map(copy, coords(shapes[1]))
|
||||
for shape in shapes[2:end]
|
||||
nanappend!(x, shape.x)
|
||||
nanappend!(y, shape.y)
|
||||
end
|
||||
x, y
|
||||
end
|
||||
|
||||
"get an array of tuples of points on a circle with radius `r`"
|
||||
function partialcircle(start_θ, end_θ, n = 20, r=1)
|
||||
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)]
|
||||
end
|
||||
|
||||
"interleave 2 vectors into each other (like a zipper's teeth)"
|
||||
function weave(x,y; ordering = Vector[x,y])
|
||||
ret = eltype(x)[]
|
||||
done = false
|
||||
while !done
|
||||
for o in ordering
|
||||
try
|
||||
push!(ret, popfirst!(o))
|
||||
catch
|
||||
end
|
||||
end
|
||||
done = isempty(x) && isempty(y)
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
|
||||
function makestar(n; offset = -0.5, radius = 1.0)
|
||||
z1 = offset * π
|
||||
z2 = z1 + π / (n)
|
||||
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
|
||||
Shape(weave(outercircle, innercircle))
|
||||
end
|
||||
|
||||
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
|
||||
function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
z = offset * π
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius))
|
||||
end
|
||||
|
||||
function makecross(; offset = -0.5, radius = 1.0)
|
||||
z2 = offset * π
|
||||
z1 = z2 - π/8
|
||||
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
|
||||
Shape(weave(outercircle, innercircle,
|
||||
ordering=Vector[outercircle,innercircle,outercircle]))
|
||||
end
|
||||
|
||||
from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle))
|
||||
|
||||
function makearrowhead(angle; h = 2.0, w = 0.4)
|
||||
tip = from_polar(angle, h)
|
||||
Shape(P2[(0,0), from_polar(angle - 0.5π, w) - tip,
|
||||
from_polar(angle + 0.5π, w) - tip, (0,0)])
|
||||
end
|
||||
|
||||
const _shapes = KW(
|
||||
:circle => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
:utriangle => makeshape(3, offset=0.5),
|
||||
:dtriangle => makeshape(3, offset=-0.5),
|
||||
:rtriangle => makeshape(3, offset=0.0),
|
||||
:ltriangle => makeshape(3, offset=1.0),
|
||||
:pentagon => makeshape(5),
|
||||
:hexagon => makeshape(6),
|
||||
:heptagon => makeshape(7),
|
||||
:octagon => makeshape(8),
|
||||
:cross => makecross(offset=-0.25),
|
||||
:xcross => makecross(),
|
||||
:vline => Shape([(0,1),(0,-1)]),
|
||||
:hline => Shape([(1,0),(-1,0)]),
|
||||
)
|
||||
|
||||
for n in [4,5,6,7,8]
|
||||
_shapes[Symbol("star$n")] = makestar(n)
|
||||
end
|
||||
|
||||
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)
|
||||
A, Cx, Cy = 0.0, 0.0, 0.0
|
||||
for i=1:n
|
||||
ip1 = i==n ? 1 : i+1
|
||||
A += x[i] * y[ip1] - x[ip1] * y[i]
|
||||
end
|
||||
A *= 0.5
|
||||
for i=1:n
|
||||
ip1 = i==n ? 1 : i+1
|
||||
m = (x[i] * y[ip1] - x[ip1] * y[i])
|
||||
Cx += (x[i] + x[ip1]) * m
|
||||
Cy += (y[i] + y[ip1]) * m
|
||||
end
|
||||
Cx / 6A, Cy / 6A
|
||||
end
|
||||
|
||||
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
sx, sy = coords(shape)
|
||||
cx, cy = c
|
||||
for i=eachindex(sx)
|
||||
sx[i] = (sx[i] - cx) * x + cx
|
||||
sy[i] = (sy[i] - cy) * y + cy
|
||||
end
|
||||
shape
|
||||
end
|
||||
|
||||
function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
shapecopy = deepcopy(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=eachindex(sx)
|
||||
sx[i] += x
|
||||
sy[i] += y
|
||||
end
|
||||
shape
|
||||
end
|
||||
|
||||
function translate(shape::Shape, x::Real, y::Real = x)
|
||||
shapecopy = deepcopy(shape)
|
||||
translate!(shapecopy, x, y)
|
||||
end
|
||||
|
||||
function rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
|
||||
(x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx
|
||||
end
|
||||
|
||||
function rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
|
||||
(y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery
|
||||
end
|
||||
|
||||
function rotate(x::Real, y::Real, θ::Real, c = center(shape))
|
||||
cx, cy = c
|
||||
rotate_x(x, y, Θ, cx, cy), rotate_y(x, y, Θ, cx, cy)
|
||||
end
|
||||
|
||||
function rotate!(shape::Shape, Θ::Real, c = center(shape))
|
||||
x, y = coords(shape)
|
||||
cx, cy = c
|
||||
for i=eachindex(x)
|
||||
xi = rotate_x(x[i], y[i], Θ, cx, cy)
|
||||
yi = rotate_y(x[i], y[i], Θ, cx, cy)
|
||||
x[i], y[i] = xi, yi
|
||||
end
|
||||
shape
|
||||
end
|
||||
|
||||
"rotate an object in space"
|
||||
function rotate(shape::Shape, Θ::Real, c = center(shape))
|
||||
shapecopy = deepcopy(shape)
|
||||
rotate!(shapecopy, Θ, c)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
mutable struct Font
|
||||
family::AbstractString
|
||||
pointsize::Int
|
||||
halign::Symbol
|
||||
valign::Symbol
|
||||
rotation::Float64
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
"""
|
||||
font(args...)
|
||||
Create a Font from a list of features. Values may be specified either as
|
||||
arguments (which are distinguished by type/value) or as keyword arguments.
|
||||
# Arguments
|
||||
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
|
||||
- `pointsize`: Integer. Size of font in points
|
||||
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
|
||||
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
|
||||
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
|
||||
- `color`: Colorant or Symbol
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> font(8)
|
||||
julia> font(family="serif",halign=:center,rotation=45.0)
|
||||
```
|
||||
"""
|
||||
function font(args...;kw...)
|
||||
|
||||
# defaults
|
||||
family = "sans-serif"
|
||||
pointsize = 14
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
rotation = 0.0
|
||||
color = colorant"black"
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
if T == Font
|
||||
family = arg.family
|
||||
pointsize = arg.pointsize
|
||||
halign = arg.halign
|
||||
valign = arg.valign
|
||||
rotation = arg.rotation
|
||||
color = arg.color
|
||||
elseif arg == :center
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
elseif arg in (:hcenter, :left, :right)
|
||||
halign = arg
|
||||
elseif arg in (:vcenter, :top, :bottom)
|
||||
valign = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
elseif T <: Symbol || T <: AbstractString
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
catch
|
||||
family = string(arg)
|
||||
end
|
||||
elseif typeof(arg) <: Integer
|
||||
pointsize = arg
|
||||
elseif typeof(arg) <: Real
|
||||
rotation = convert(Float64, arg)
|
||||
else
|
||||
@warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
for symbol in keys(kw)
|
||||
if symbol == :family
|
||||
family = kw[:family]
|
||||
elseif symbol == :pointsize
|
||||
pointsize = kw[:pointsize]
|
||||
elseif symbol == :halign
|
||||
halign = kw[:halign]
|
||||
if halign == :center
|
||||
halign = :hcenter
|
||||
end
|
||||
@assert halign in (:hcenter, :left, :right)
|
||||
elseif symbol == :valign
|
||||
valign = kw[:valign]
|
||||
if valign == :center
|
||||
valign = :vcenter
|
||||
end
|
||||
@assert valign in (:vcenter, :top, :bottom)
|
||||
elseif symbol == :rotation
|
||||
rotation = kw[:rotation]
|
||||
elseif symbol == :color
|
||||
color = parse(Colorant, kw[:color])
|
||||
else
|
||||
@warn("Unused font kwarg: $symbol")
|
||||
end
|
||||
end
|
||||
|
||||
Font(family, pointsize, halign, valign, rotation, color)
|
||||
end
|
||||
|
||||
function scalefontsize(k::Symbol, factor::Number)
|
||||
f = default(k)
|
||||
f = round(Int, factor * f)
|
||||
default(k, f)
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes(factor::Number)
|
||||
|
||||
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
|
||||
"""
|
||||
function scalefontsizes(factor::Number)
|
||||
for k in (:titlefontsize, :legendfontsize, :legendtitlefontsize)
|
||||
scalefontsize(k, factor)
|
||||
end
|
||||
|
||||
for letter in (:x,:y,:z)
|
||||
for k in (:guidefontsize, :tickfontsize)
|
||||
scalefontsize(Symbol(letter, k), factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes()
|
||||
|
||||
Resets font sizes to initial default values.
|
||||
"""
|
||||
function scalefontsizes()
|
||||
for k in (:titlefontsize, :legendfontsize, :legendtitlefontsize)
|
||||
f = default(k)
|
||||
if k in keys(_initial_fontsizes)
|
||||
factor = f / _initial_fontsizes[k]
|
||||
scalefontsize(k, 1.0/factor)
|
||||
end
|
||||
end
|
||||
|
||||
for letter in (:x,:y,:z)
|
||||
for k in (:guidefontsize, :tickfontsize)
|
||||
if k in keys(_initial_fontsizes)
|
||||
f = default(Symbol(letter, k))
|
||||
factor = f / _initial_fontsizes[k]
|
||||
scalefontsize(Symbol(letter, k), 1.0/factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resetfontsizes() = scalefontsizes()
|
||||
|
||||
"Wrap a string with font info"
|
||||
struct PlotText
|
||||
str::AbstractString
|
||||
font::Font
|
||||
end
|
||||
PlotText(str) = PlotText(string(str), font())
|
||||
|
||||
"""
|
||||
text(string, args...; kw...)
|
||||
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations.
|
||||
`args` and `kw` are passed to `font`.
|
||||
"""
|
||||
text(t::PlotText) = t
|
||||
text(t::PlotText, font::Font) = PlotText(t.str, font)
|
||||
text(str::AbstractString, f::Font) = PlotText(str, f)
|
||||
function text(str, args...;kw...)
|
||||
PlotText(string(str), font(args...;kw...))
|
||||
end
|
||||
|
||||
Base.length(t::PlotText) = length(t.str)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
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
|
||||
style = :solid
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
# if arg in _allStyles
|
||||
if allStyles(arg)
|
||||
style = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
elseif T <: Symbol || T <: AbstractString
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
catch
|
||||
end
|
||||
elseif allAlphas(arg)
|
||||
alpha = arg
|
||||
elseif allReals(arg)
|
||||
width = arg
|
||||
else
|
||||
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
Stroke(width, color, alpha, style)
|
||||
end
|
||||
|
||||
|
||||
struct Brush
|
||||
size # fillrange, markersize, or any other sizey attribute
|
||||
color
|
||||
alpha
|
||||
end
|
||||
|
||||
function brush(args...; alpha = nothing)
|
||||
size = 1
|
||||
color = :black
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
if T <: Colorant
|
||||
color = arg
|
||||
elseif T <: Symbol || T <: AbstractString
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
catch
|
||||
end
|
||||
elseif allAlphas(arg)
|
||||
alpha = arg
|
||||
elseif allReals(arg)
|
||||
size = arg
|
||||
else
|
||||
@warn("Unused brush arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
Brush(size, color, alpha)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
mutable struct SeriesAnnotations
|
||||
strs::AbstractVector # the labels/names
|
||||
font::Font
|
||||
baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
|
||||
scalefactor::Tuple
|
||||
end
|
||||
function series_annotations(strs::AbstractVector, args...)
|
||||
fnt = font()
|
||||
shp = nothing
|
||||
scalefactor = (1,1)
|
||||
for arg in args
|
||||
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
|
||||
shp = arg
|
||||
elseif isa(arg, Font)
|
||||
fnt = arg
|
||||
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
||||
shp = _shapes[arg]
|
||||
elseif isa(arg, Number)
|
||||
scalefactor = (arg,arg)
|
||||
elseif is_2tuple(arg)
|
||||
scalefactor = arg
|
||||
else
|
||||
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
# if scalefactor != 1
|
||||
# for s in get(shp)
|
||||
# scale!(s, scalefactor, scalefactor, (0,0))
|
||||
# end
|
||||
# end
|
||||
SeriesAnnotations(strs, fnt, shp, scalefactor)
|
||||
end
|
||||
series_annotations(anns::SeriesAnnotations) = anns
|
||||
series_annotations(::Nothing) = nothing
|
||||
|
||||
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
anns = series[:series_annotations]
|
||||
# msw,msh = anns.scalefactor
|
||||
# ms = series[:markersize]
|
||||
# msw,msh = if isa(ms, AbstractVector)
|
||||
# 1,1
|
||||
# elseif is_2tuple(ms)
|
||||
# ms
|
||||
# else
|
||||
# ms,ms
|
||||
# end
|
||||
|
||||
# @show msw msh
|
||||
if anns !== nothing && anns.baseshape !== nothing
|
||||
# we use baseshape to overwrite the markershape attribute
|
||||
# with a list of custom shapes for each
|
||||
msw,msh = anns.scalefactor
|
||||
msize = Float64[]
|
||||
shapes = Vector{Shape}(undef, length(anns.strs))
|
||||
for i in eachindex(anns.strs)
|
||||
str = _cycle(anns.strs,i)
|
||||
|
||||
# get the width and height of the string (in mm)
|
||||
sw, sh = text_size(str, anns.font.pointsize)
|
||||
|
||||
# how much to scale the base shape?
|
||||
# note: it's a rough assumption that the shape fills the unit box [-1,-1,1,1],
|
||||
# so we scale the length-2 shape by 1/2 the total length
|
||||
scalar = (backend() == PyPlotBackend() ? 1.7 : 1.0)
|
||||
xscale = 0.5to_pixels(sw) * scalar
|
||||
yscale = 0.5to_pixels(sh) * scalar
|
||||
|
||||
# we save the size of the larger direction to the markersize list,
|
||||
# and then re-scale a copy of baseshape to match the w/h ratio
|
||||
maxscale = max(xscale, yscale)
|
||||
push!(msize, maxscale)
|
||||
baseshape = _cycle(anns.baseshape, i)
|
||||
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
|
||||
end
|
||||
series[:markershape] = shapes
|
||||
series[:markersize] = msize
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
mutable struct EachAnn
|
||||
anns
|
||||
x
|
||||
y
|
||||
end
|
||||
|
||||
function Base.iterate(ea::EachAnn, i = 1)
|
||||
if ea.anns === nothing || isempty(ea.anns.strs) || i > length(ea.y)
|
||||
return nothing
|
||||
end
|
||||
|
||||
tmp = _cycle(ea.anns.strs,i)
|
||||
str,fnt = if isa(tmp, PlotText)
|
||||
tmp.str, tmp.font
|
||||
else
|
||||
tmp, ea.anns.font
|
||||
end
|
||||
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
|
||||
end
|
||||
|
||||
annotations(::Nothing) = []
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns) = Any[anns]
|
||||
annotations(sa::SeriesAnnotations) = sa
|
||||
|
||||
# Expand arrays of coordinates, positions and labels into induvidual annotations
|
||||
# and make sure labels are of type PlotText
|
||||
function process_annotation(sp::Subplot, xs, ys, labs, font = font())
|
||||
anns = []
|
||||
labs = makevec(labs)
|
||||
xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs)
|
||||
ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys)
|
||||
for i in 1:max(xlength, ylength, length(labs))
|
||||
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
|
||||
x = typeof(x) <: TimeType ? Dates.value(x) : x
|
||||
y = typeof(y) <: TimeType ? Dates.value(y) : y
|
||||
if lab == :auto
|
||||
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
|
||||
else
|
||||
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
|
||||
end
|
||||
end
|
||||
anns
|
||||
end
|
||||
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font())
|
||||
anns = []
|
||||
positions, labs = makevec(positions), makevec(labs)
|
||||
for i in 1:max(length(positions), length(labs))
|
||||
pos, lab = _cycle(positions, i), _cycle(labs, i)
|
||||
pos = get(_positionAliases, pos, pos)
|
||||
if lab == :auto
|
||||
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
|
||||
else
|
||||
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
|
||||
end
|
||||
end
|
||||
anns
|
||||
end
|
||||
|
||||
function process_any_label(lab, font=Font())
|
||||
lab isa Tuple ? text(lab...) : text( lab, font )
|
||||
end
|
||||
# Give each annotation coordinates based on specified position
|
||||
function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
|
||||
position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}(
|
||||
:topleft => (0.1, 0.9),
|
||||
:topcenter => (0.5, 0.9),
|
||||
:topright => (0.9, 0.9),
|
||||
:bottomleft => (0.1, 0.1),
|
||||
:bottomcenter => (0.5, 0.1),
|
||||
:bottomright => (0.9, 0.1),
|
||||
)
|
||||
xmin, xmax = ignorenan_extrema(sp[:xaxis])
|
||||
ymin, ymax = ignorenan_extrema(sp[:yaxis])
|
||||
x, y = (xmin, ymin).+ position_multiplier[pos].* (xmax - xmin, ymax - ymin)
|
||||
(x, y, lab)
|
||||
end
|
||||
locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label)
|
||||
locate_annotation(sp::Subplot, x, y, z, label::PlotText) = (x, y, z, label)
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"type which represents z-values for colors and sizes (and anything else that might come up)"
|
||||
struct ZValues
|
||||
values::Vector{Float64}
|
||||
zrange::Tuple{Float64,Float64}
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
function expand_extrema!(a::Axis, surf::Surface)
|
||||
ex = a[:extrema]
|
||||
for vi in surf.surf
|
||||
expand_extrema!(ex, vi)
|
||||
end
|
||||
ex
|
||||
end
|
||||
|
||||
"For the case of representing a surface as a function of x/y... can possibly avoid allocations."
|
||||
struct SurfaceFunction <: AbstractSurface
|
||||
f::Function
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# # I don't want to clash with ValidatedNumerics, but this would be nice:
|
||||
# ..(a::T, b::T) = (a,b)
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# style is :open or :closed (for now)
|
||||
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
|
||||
headlength = 0.3
|
||||
headwidth = 0.3
|
||||
setlength = false
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
if T == Symbol
|
||||
if arg in (:head, :tail, :both)
|
||||
side = arg
|
||||
else
|
||||
style = arg
|
||||
end
|
||||
elseif T <: Number
|
||||
# first we apply to both, but if there's more, then only change width after the first number
|
||||
headwidth = Float64(arg)
|
||||
if !setlength
|
||||
headlength = headwidth
|
||||
end
|
||||
setlength = true
|
||||
elseif T <: Tuple && length(arg) == 2
|
||||
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
|
||||
else
|
||||
@warn("Skipped arrow arg $arg")
|
||||
end
|
||||
end
|
||||
Arrow(style, side, headlength, headwidth)
|
||||
end
|
||||
|
||||
|
||||
# allow for do-block notation which gets called on every valid start/end pair which
|
||||
# we need to draw an arrow
|
||||
function add_arrows(func::Function, x::AVec, y::AVec)
|
||||
for i=2:length(x)
|
||||
xyprev = (x[i-1], y[i-1])
|
||||
xy = (x[i], y[i])
|
||||
if ok(xyprev) && ok(xy)
|
||||
if i==length(x) || !ok(x[i+1], y[i+1])
|
||||
# add the arrow from xyprev to xy
|
||||
func(xyprev, xy)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
"create a BezierCurve for plotting"
|
||||
mutable struct BezierCurve{T <: GeometryBasics.Point}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
function (bc::BezierCurve)(t::Real)
|
||||
p = zero(P2)
|
||||
n = length(bc.control_points)-1
|
||||
for i in 0:n
|
||||
p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
|
||||
end
|
||||
p
|
||||
end
|
||||
|
||||
@deprecate curve_points coords
|
||||
|
||||
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, Base.range(first(range), stop=last(range), length=n))
|
||||
|
||||
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
|
||||
# may create a loop if necessary. Assumes the view is [0,1]
|
||||
function directed_curve(args...; kw...)
|
||||
error("directed_curve has been moved to PlotRecipes")
|
||||
end
|
||||
|
||||
function extrema_plus_buffer(v, buffmult = 0.2)
|
||||
vmin,vmax = ignorenan_extrema(v)
|
||||
vdiff = vmax-vmin
|
||||
buffer = vdiff * buffmult
|
||||
vmin - buffer, vmax + buffer
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
# ---------------------------------------------------------
|
||||
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
|
||||
|
||||
_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString)
|
||||
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x)
|
||||
|
||||
function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
|
||||
fn = tempname()
|
||||
|
||||
# first save a pdf file
|
||||
pdf(plt, fn)
|
||||
|
||||
# load that pdf into a FileIO Stream
|
||||
s = _fileio_load(fn * ".pdf")
|
||||
|
||||
# save a png
|
||||
pngfn = fn * ".png"
|
||||
_fileio_save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, read(open(pngfn), String))
|
||||
end
|
||||
|
||||
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
|
||||
@@ -0,0 +1,62 @@
|
||||
const use_local_dependencies = Ref(false)
|
||||
const use_local_plotlyjs = Ref(false)
|
||||
|
||||
|
||||
function _init_ijulia_plotting()
|
||||
# IJulia is more stable with local file
|
||||
use_local_plotlyjs[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Add extra jupyter mimetypes to display_dict based on the plot backed.
|
||||
|
||||
The default is nothing, except for plotly based backends, where it
|
||||
adds data for `application/vnd.plotly.v1+json` that is used in
|
||||
frontends like jupyterlab and nteract.
|
||||
"""
|
||||
_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out
|
||||
|
||||
function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
|
||||
function _ijulia_display_dict(plt::Plot)
|
||||
output_type = Symbol(plt.attr[:html_output_format])
|
||||
if output_type == :auto
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
out = Dict()
|
||||
if output_type == :txt
|
||||
mime = "text/plain"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :png
|
||||
mime = "image/png"
|
||||
out[mime] = base64encode(show, MIME(mime), plt)
|
||||
elseif output_type == :svg
|
||||
mime = "image/svg+xml"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :html
|
||||
mime = "text/html"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
_ijulia__extra_mime_info!(plt, out)
|
||||
else
|
||||
error("Unsupported output type $output_type")
|
||||
end
|
||||
out
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
using REPL
|
||||
using Scratch
|
||||
|
||||
const plotly_local_file_path = Ref{Union{Nothing, String}}(nothing)
|
||||
|
||||
|
||||
function _plots_defaults()
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
copy(Dict{Symbol,Any}(Main.PLOTS_DEFAULTS))
|
||||
else
|
||||
Dict{Symbol,Any}()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function __init__()
|
||||
user_defaults = _plots_defaults()
|
||||
if haskey(user_defaults, :theme)
|
||||
theme(pop!(user_defaults, :theme); user_defaults...)
|
||||
else
|
||||
default(; user_defaults...)
|
||||
end
|
||||
|
||||
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
|
||||
|
||||
atreplinit(i -> begin
|
||||
while PlotsDisplay() in Base.Multimedia.displays
|
||||
popdisplay(PlotsDisplay())
|
||||
end
|
||||
insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
|
||||
end)
|
||||
|
||||
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin
|
||||
fn = joinpath(@__DIR__, "backends", "hdf5.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" begin
|
||||
fn = joinpath(@__DIR__, "backends", "inspectdr.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" begin
|
||||
fn = joinpath(@__DIR__, "backends", "deprecated", "pgfplots.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" begin
|
||||
fn = joinpath(@__DIR__, "backends", "plotlybase.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin
|
||||
fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin
|
||||
fn = joinpath(@__DIR__, "backends", "plotlyjs.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" begin
|
||||
fn = joinpath(@__DIR__, "backends", "pyplot.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" begin
|
||||
fn = joinpath(@__DIR__, "backends", "unicodeplots.jl")
|
||||
include(fn)
|
||||
end
|
||||
|
||||
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
|
||||
if IJulia.inited
|
||||
_init_ijulia_plotting()
|
||||
|
||||
IJulia.display_dict(plt::Plot) = _ijulia_display_dict(plt)
|
||||
end
|
||||
end
|
||||
|
||||
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
|
||||
global plotly_local_file_path[] = joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
|
||||
if !isfile(plotly_local_file_path[])
|
||||
download("https://cdn.plot.ly/$(_plotly_min_js_filename)", plotly_local_file_path[])
|
||||
end
|
||||
|
||||
use_local_plotlyjs[] = true
|
||||
end
|
||||
|
||||
use_local_dependencies[] = use_local_plotlyjs[]
|
||||
|
||||
|
||||
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
|
||||
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt)
|
||||
end
|
||||
end
|
||||