Compare commits
2325 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90e0074f44 | |||
| 3e14a47e17 | |||
| 5d608d1e77 | |||
| 20e24cfa8d | |||
| 2d0191cd70 | |||
| 12d5accf0a | |||
| c02dbca31d | |||
| 0e25767cd3 | |||
| 5d935d29c5 | |||
| f5e6ae9f98 | |||
| 4a18098944 | |||
| 3994e47d3c | |||
| 39d52a5c57 | |||
| 91e91ac821 | |||
| e9949251a6 | |||
| 16e41f0690 | |||
| 6f4400411e | |||
| 1bba6afde5 | |||
| 909ad3314a | |||
| 68a56fee91 | |||
| 9f4e32aa4d | |||
| 434e189f1e | |||
| c9f7c6b45d | |||
| e58fdf970f | |||
| c97900f7ee | |||
| 1b881619e3 | |||
| fbd5d79d49 | |||
| db7420fd5f | |||
| 09356ee3b5 | |||
| 0122d70640 | |||
| 5974d0ac31 | |||
| 81170b4342 | |||
| ee316e2913 | |||
| ef93aa87be | |||
| 88ebb8152d | |||
| 124d2d6aa3 | |||
| cdbafd60c8 | |||
| 5eb62abb25 | |||
| 3f110d6a6c | |||
| 293b43013b | |||
| 3536acbcc8 | |||
| 0ca5bc9124 | |||
| 14b38354da | |||
| 06c551ba51 | |||
| f63ee6d79e | |||
| b3f698c460 | |||
| 829860fa2d | |||
| 1523ef67d5 | |||
| e049b082f3 | |||
| f78899a1ef | |||
| e42b4ad34d | |||
| a7c629f775 | |||
| 1ddc673201 | |||
| bba971f7ea | |||
| 3f9105054c | |||
| a64ae3d13c | |||
| 7b0066c433 | |||
| d657c0cb33 | |||
| 50f63cf1eb | |||
| 2b22dae757 | |||
| 7ca32b5edd | |||
| 3f5a1287be | |||
| 990e0f3f7f | |||
| 849d31d57f | |||
| cfe5ba24a6 | |||
| be1c263df9 | |||
| 203af856cd | |||
| 019a742c84 | |||
| 5330776040 | |||
| fcdb3c1c0d | |||
| cc290818d7 | |||
| 14b3852060 | |||
| 387f918080 | |||
| d0d95c6cc7 | |||
| d51059f0e9 | |||
| 4723c513be | |||
| d1373d8b89 | |||
| 9f51b96269 | |||
| 601df0c9a9 | |||
| 700b5782ec | |||
| 6a62d96751 | |||
| 25b57cfb55 | |||
| fb390d1872 | |||
| 5fafddb995 | |||
| 697e5a87cf | |||
| 77ba81de19 | |||
| e43f3ee373 | |||
| 8f055fef3d | |||
| ce530ef518 | |||
| 827462dc21 | |||
| 1ecec912a1 | |||
| ca8e775b83 | |||
| c0e50588d3 | |||
| de7717b85f | |||
| a1311e5c60 | |||
| 4069b73563 | |||
| a7d6e93af3 | |||
| 058983165e | |||
| 97036e689e | |||
| d3589db840 | |||
| 15bd9c537d | |||
| 27764bbc67 | |||
| 788e28d18a | |||
| d544647b1b | |||
| 3cb81d6d04 | |||
| 61f2d825b6 | |||
| 5df64bd45b | |||
| 7e997da6bd | |||
| 35658bf4fe | |||
| f355ff9904 | |||
| 8893782b13 | |||
| 78f7db138f | |||
| 23567964e7 | |||
| 0c7f7ba011 | |||
| 4731477920 | |||
| 57ba6aa5a9 | |||
| 3c472f24b5 | |||
| 5a4651a0ec | |||
| 7bb2132b18 | |||
| fd50469e20 | |||
| e3d13aa17a | |||
| 476de3d2a2 | |||
| c986bfa1e6 | |||
| dfd8fada9d | |||
| d4298bf1cc | |||
| 02437562a7 | |||
| 8cf268a390 | |||
| fbf3878ca5 | |||
| e449d3221c | |||
| a359f21325 | |||
| 9da550ba3b | |||
| 0a7035979f | |||
| 6376d40ae2 | |||
| 67f4d79c4a | |||
| 50adb6cd9c | |||
| 64f3d589b6 | |||
| 07b05e075e | |||
| 1ceb3a561f | |||
| e1e0f8d1c9 | |||
| f39ba03da5 | |||
| 7d7212ba3e | |||
| 17a942998d | |||
| 6a829e2b1a | |||
| 011591ff55 | |||
| c56654c6cf | |||
| 90255913a4 | |||
| 67d7b4d771 | |||
| 3051ce9e57 | |||
| 09e90c0ca6 | |||
| dbe9a2c52b | |||
| 56a0673713 | |||
| 22f1dd72c9 | |||
| 9ad3654d4f | |||
| d2c85bdff9 | |||
| ec7a912b58 | |||
| b63e41904b | |||
| 78f078ccc2 | |||
| 727ced25f1 | |||
| 378cabcb73 | |||
| f4fb0862ea | |||
| cda8dae829 | |||
| 86c400500e | |||
| 23f8ba1db8 | |||
| 014b86a44c | |||
| 0ac71c6b1e | |||
| 29604fd7f2 | |||
| 53272b8a9d | |||
| a0b104f563 | |||
| 9581a7cc49 | |||
| 7d22d84595 | |||
| bf23b8f7a1 | |||
| 005dcbc77a | |||
| ad1216639a | |||
| ce778ff7be | |||
| 711a8448dc | |||
| 0a84ff8caf | |||
| 23cbfe9378 | |||
| 1cb434ac26 | |||
| 138a2fa34a | |||
| 60c59a4be0 | |||
| bea1378ff1 | |||
| d46f59e4be | |||
| 52da386df1 | |||
| bb26bb0557 | |||
| b3bf5db9bc | |||
| 074c56867d | |||
| 71fd38fe26 | |||
| 4841c13311 | |||
| 89dea71874 | |||
| 1a9532f9fc | |||
| 2b3fa980ee | |||
| 0d528b7c82 | |||
| c2cb60ff12 | |||
| ddf6aa9760 | |||
| 50f1106cd7 | |||
| 3bb406e0ea | |||
| 10fa36cdd9 | |||
| 0508d05299 | |||
| 59a1faf590 | |||
| c0824bdc62 | |||
| 606b86c962 | |||
| a50661dd44 | |||
| 34f4d318ea | |||
| 9fc1d574cd | |||
| 9300dffcc3 | |||
| 796f9ef47b | |||
| da2dc2cb1b | |||
| f76390c20d | |||
| ef82e53eef | |||
| 219939525c | |||
| ae99ed2588 | |||
| 8e13bb4ccc | |||
| 66db3ceae0 | |||
| 060162c356 | |||
| 271d93c1ed | |||
| 664af999cd | |||
| a1ace08d22 | |||
| 4d5f76b80d | |||
| b8c2d62c32 | |||
| 6201dfe580 | |||
| d44b7e89e7 | |||
| 08e3224f8f | |||
| e9b78e7191 | |||
| f418acf387 | |||
| f097549e3b | |||
| c8b882d17a | |||
| dbbece413c | |||
| 9cee7a2c47 | |||
| d6a72a5df5 | |||
| 37252ec562 | |||
| 1d3e0a5d5d | |||
| a85c10dcdd | |||
| 97caa18fb4 | |||
| 6af91c7f71 | |||
| e9cd69ea2f | |||
| 6724a3a2fe | |||
| a75d309d20 | |||
| 5cc08a17b6 | |||
| 2220dbc465 | |||
| 66250acfaa | |||
| 395cc9294b | |||
| 3f13a186e7 | |||
| 2d8b2332fb | |||
| 2cee039dbc | |||
| 6193519b1f | |||
| 65dac58338 | |||
| 164725079d | |||
| 42b3c5625f | |||
| cd851df28a | |||
| 57b0a81c1c | |||
| 1ef15934cc | |||
| 0a6edd5d60 | |||
| e8437d76fd | |||
| 2e2f7044e2 | |||
| 100da5ccae | |||
| d59f6c96d5 | |||
| 0628fb9dc3 | |||
| 6b71bd961d | |||
| 9569f34ae0 | |||
| d830f64cbc | |||
| dd785c3bd3 | |||
| 663d556a06 | |||
| e06a51b420 | |||
| da3e0294cd | |||
| 57e98ac12d | |||
| 740f231d5f | |||
| cf96ddcd30 | |||
| ec532b2cbb | |||
| 7989673eb4 | |||
| 897a5eee87 | |||
| 0665ff907c | |||
| 1fc0892551 | |||
| 8d7375dc4f | |||
| 2594b577d7 | |||
| 9b174084f7 | |||
| d196952571 | |||
| df8fe4d28b | |||
| 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 | |||
| 85b3aefd67 | |||
| af0dabec99 | |||
| de85983247 | |||
| 7eaae3a6d5 | |||
| 403b57c076 | |||
| dd434b89d2 | |||
| 1a3d58e09b | |||
| 89ae239743 | |||
| c785d1509b | |||
| 9e412555bb | |||
| 0717805773 | |||
| d045c5a390 | |||
| 3cc0d0c735 | |||
| 9a3c727532 | |||
| a7f2484d45 | |||
| 96d97699a0 | |||
| e92e832258 | |||
| 3a769549d8 | |||
| d68829820b | |||
| 9cf3036ab5 | |||
| 2467eb71c1 | |||
| 345bb5d1aa | |||
| 8d50828998 | |||
| 201de82baf | |||
| 99519ac3da | |||
| a575ab7c74 | |||
| c4f79814df | |||
| 6135f6271c | |||
| 5b0ba79a35 | |||
| 173c7b2aec | |||
| 1a67ca897c |
@@ -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 <backend(s)>`):
|
||||
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'
|
||||
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,89 @@
|
||||
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);'
|
||||
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots");'
|
||||
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes");'
|
||||
|
||||
- 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
|
||||
@@ -0,0 +1,50 @@
|
||||
name: docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags: '*'
|
||||
|
||||
jobs:
|
||||
Build_docs:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: JuliaPlots/PlotDocs.jl
|
||||
- uses: julia-actions/setup-julia@v1
|
||||
- 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 }}-
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y qt5-default \
|
||||
ttf-mscorefonts-installer \
|
||||
poppler-utils \
|
||||
pdf2svg \
|
||||
texlive-latex-base \
|
||||
texlive-binaries \
|
||||
texlive-pictures \
|
||||
texlive-latex-extra \
|
||||
texlive-luatex \
|
||||
ghostscript-x \
|
||||
libgconf2-4
|
||||
sudo fc-cache -vr
|
||||
|
||||
- name: build documentation
|
||||
env:
|
||||
PYTHON: ""
|
||||
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
|
||||
run: |
|
||||
xvfb-run julia --color=yes --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.add(PackageSpec(name="Plots", rev=split(ENV["GITHUB_REF"], "/", limit=3)[3])); Pkg.instantiate()'
|
||||
xvfb-run julia --color=yes --project=docs/ -e 'withenv("GITHUB_REPOSITORY" => "JuliaPlots/PlotDocs.jl") do; include("docs/make.jl"); end'
|
||||
+9
-1
@@ -4,4 +4,12 @@
|
||||
.DS_Store
|
||||
examples/.ipynb_checkpoints/*
|
||||
examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-latest.min.js
|
||||
deps/plotly-*
|
||||
deps/build.log
|
||||
deps/deps.jl
|
||||
Manifest.toml
|
||||
dev/
|
||||
test/tmpplotsave.hdf5
|
||||
/.benchmarkci
|
||||
/benchmark/*.json
|
||||
.vscode/
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
# Documentation: http://docs.travis-ci.com/user/languages/julia/
|
||||
language: julia
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
julia:
|
||||
- 0.6
|
||||
matrix:
|
||||
allow_failures:
|
||||
- julia: nightly
|
||||
|
||||
# # before install:
|
||||
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install wkhtmltopdf; fi
|
||||
|
||||
# ref: http://askubuntu.com/a/556672 for the wkhtmltopdf apt repository info
|
||||
|
||||
sudo: required
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test/install_wkhtmltoimage.sh ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:pov/wkhtmltopdf ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y wkhtmltopdf ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltopdf -V ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltoimage -V ; fi
|
||||
# echo 'exec xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@"' | sudo tee /usr/local/bin/wkhtmltopdf.sh >/dev/null
|
||||
# sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh
|
||||
|
||||
# # borrowed from Blink.jl's travis file
|
||||
# matrix:
|
||||
# include:
|
||||
# - os: linux
|
||||
# julia: 0.4
|
||||
# env: TESTCMD="xvfb-run julia"
|
||||
# - os: osx
|
||||
# julia: 0.4
|
||||
# env: TESTCMD="julia"
|
||||
|
||||
|
||||
|
||||
notifications:
|
||||
email: true
|
||||
# uncomment the following lines to override the default test script
|
||||
script:
|
||||
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
|
||||
- julia test/travis_commands.jl
|
||||
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
|
||||
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
|
||||
# - julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/JunoLab/Blink.jl.git"); Pkg.build("Blink"); import Blink; Blink.AtomShell.install()'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")'
|
||||
# - julia -e 'ENV["PYTHON"] = ""; Pkg.add("PyPlot"); Pkg.build("PyPlot")'
|
||||
#
|
||||
# # - $TESTCMD -e 'Pkg.test("Plots"; coverage=false)'
|
||||
# - julia -e 'Pkg.test("Plots"; coverage=false)'
|
||||
# # - julia -e 'cd(Pkg.dir("Plots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
{
|
||||
"title": "Plots.jl",
|
||||
"license": "MIT",
|
||||
"creators": [
|
||||
{
|
||||
"affiliation": "Elemental Cognition",
|
||||
"name": "Tom Breloff"
|
||||
}
|
||||
],
|
||||
"contributors":[
|
||||
{
|
||||
"affiliation": "TU Wien",
|
||||
"name": "Daniel Schwabeneder",
|
||||
"orcid": "0000-0002-0412-0777",
|
||||
"type": "ProjectLeader"
|
||||
},
|
||||
{
|
||||
"affiliation": "GLOBE Institute, University of Copenhagen",
|
||||
"name": "Michael Krabbe Borregaard",
|
||||
"orcid": "0000-0002-8146-8435",
|
||||
"type": "ProjectLeader"
|
||||
},
|
||||
{
|
||||
"affiliation": "Leibniz Universit\u00e4t Hannover",
|
||||
"name": "Simon Christ",
|
||||
"orcid": "0000-0002-5866-1472",
|
||||
"type": "ProjectLeader"
|
||||
},
|
||||
{
|
||||
"affiliation": "Forschungszentrum J\u00fclich",
|
||||
"name": "Josef Heinen",
|
||||
"orcid": "0000-0001-6509-1925",
|
||||
"type": "ProjectMember"
|
||||
},
|
||||
{
|
||||
"name": "Yuval",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Palugniok",
|
||||
"type": "ProjectMember"
|
||||
},
|
||||
{
|
||||
"affiliation": "@beacon-biosignals",
|
||||
"name": "Simon Danisch",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "Veos Digital (https://veos.digital/)",
|
||||
"name": "Pietro Vertechi",
|
||||
"type": "ProjectMember"
|
||||
},
|
||||
{
|
||||
"affiliation": "Korea Advanced Inst. of Science and Technology (KAIST)",
|
||||
"name": "Zhanibek Omarov",
|
||||
"type": "ProjectMember",
|
||||
"orcid": "0000-0002-8783-8791"
|
||||
},
|
||||
{
|
||||
"name": "Thatcher Chamberlin",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@ma-laforge",
|
||||
"type": "ProjectMember"
|
||||
},
|
||||
{
|
||||
"affiliation": "Massachusetts Institute of Technology",
|
||||
"name": "Christopher Rackauckas",
|
||||
"orcid": "0000-0001-5850-0663",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "Max Planck Institute for Physics",
|
||||
"name": "Oliver Schulz",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "@JuliaComputing",
|
||||
"name": "Sebastian Pfitzner",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Takafumi Arakaki",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "University of Manitoba",
|
||||
"name": "Amin Yahyaabadi",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jack Devine",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Pech",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "@JuliaComputing",
|
||||
"name": "Patrick Kofod Mogensen",
|
||||
"type": "Other",
|
||||
"orcid": "0000-0002-4910-1932"
|
||||
},
|
||||
{
|
||||
"name": "Samuel S. Watson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "UC Davis",
|
||||
"name": "Naoki Saito",
|
||||
"orcid": "0000-0001-5234-4719",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "University of Southern California (USC)",
|
||||
"name": "Benoit Pasquier",
|
||||
"orcid": "0000-0002-3838-5976",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "NTNU Trondheim",
|
||||
"name": "Ronny Bergmann",
|
||||
"orcid": "0000-0001-8342-7218",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Andy Nowacki",
|
||||
"affiliation": "University of Leeds",
|
||||
"orcid": "0000-0001-7669-7383",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Ian Butterworth",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "Lund University",
|
||||
"name": "David Gustavsson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Anshul Singhvi",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "david-macmahon",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Fredrik Ekre",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Maaz Bin Tahir Saeed",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Kristoffer Carlsson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Will Kearney",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Niklas Korsbo",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Miles Lucas",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@Godisemo",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Florian Oswald",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Diego Javier Zea",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@WillRam",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Fedor Bezrukov",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Spencer Lyon",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Darwin Darakananda",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Lukas Hauertmann",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Huckleberry Febbo",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@H-M-H",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Josh Day",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@wfgra",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Sheehan Olver",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jerry Ling",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jks Liu",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Seth Axen",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@o01eg",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Micluța-Câmpeanu",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Tim Holy",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Tony Kelman",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Antoine Levitt",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Iblis Lin",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Harry Scholes",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@djsegal",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Goran Nakerst",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Felix Hagemann",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Matthieu Gomez",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@biggsbiggsby",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Anderson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Michael Kraus",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Carlo Lucibello",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Robin Deits",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Misha Mkhasenko",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Benoît Legat",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Steven G. Johnson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "John Verzani",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Mattias Fält",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Rashika Karki",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Morten Piibeleht",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Filippo Vicentini",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "David Anthoff",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Leon Wabeke",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Yusuke Kominami",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Oscar Dowson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Max G",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Fabian Greimel",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jérémy",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Pearl Li",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "David P. Sanders",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Asbjørn Nilsen Riseth",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jan Weidner",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@jakkor2",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Pablo Zubieta",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Hamza Yusuf Çakır",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "John Rinehart",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Martin Biel",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Moritz Schauer",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Moesè Giodano",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@olegshtch",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Leon Shen",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jeff Fessler",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@hustf",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Asim H Dar",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@8uurg",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Abel Siqueira",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Adrian Dawid",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Alberto Lusiani",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Balázs Mezei",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Ben Ide",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Lungwitz",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "University of Graz",
|
||||
"name": "Bernd Riederer",
|
||||
"type": "Other",
|
||||
"orcid": "0000-0001-8390-0087"
|
||||
},
|
||||
{
|
||||
"name": "Christina Lee",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Christof Stocker",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Christoph Finkensiep",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@Cornelius-G",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Daniel Høegh",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Denny Biasiolli",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Dieter Castel",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Elliot Saba",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Fengyang Wang",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Fons van der Plas",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Fredrik Bagge Carlson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Graham Smith",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Hayato Ikoma",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Hessam Mehr",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@InfiniteChai",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jack Dunn",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jeff Bezanson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jeff Eldredge",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jinay Jain",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Johan Blåbäck",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@jmert",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Lakshya Khatri",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Lia Siegelmann",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@marekkukan-tw",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "ETH Zurich",
|
||||
"name": "Mauro Werder",
|
||||
"type": "Other",
|
||||
"orcid": "0000-0003-0137-9377"
|
||||
},
|
||||
{
|
||||
"name": "Maxim Grechkin",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Michael Cawte",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@milesfrain",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Nicholas Bauer",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Nicolau Leal Werneck",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@nilshg",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Oliver Evans",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Peter Gagarinov",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Páll Haraldsson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Rik Huijzer",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Romain Franconville",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Ronan Pigott",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Roshan Shariff",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Scott Thomas",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Rollén",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Seth Bromberger",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Siva Swaminathan",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Tim DuBois",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Travis DePrato",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Will Thompson",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Yakir Luc Gagnon",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Chislett",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@hhaensel",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@improbable22",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Fleck",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Peter Czaban",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@innerlee",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Mats Cronqvist",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Shi Pengcheng",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@wg030",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"affiliation": "University of Cambridge",
|
||||
"name": "Will Tebbutt",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "@t-bltg",
|
||||
"type": "Other"
|
||||
}
|
||||
{
|
||||
"name": "Fred Callaway",
|
||||
"type": "Other"
|
||||
}
|
||||
],
|
||||
"upload_type": "software"
|
||||
}
|
||||
@@ -3,14 +3,185 @@
|
||||
|
||||
#### notes on release changes, ongoing development, and future planned work
|
||||
|
||||
- Minor version 0.17 is the last one to support Julia 0.6!!
|
||||
- Minor version 0.11 is the last one to support Julia 0.5!!
|
||||
- Critical bugfixes only
|
||||
- `backports` branch is for Julia 0.5
|
||||
|
||||
---
|
||||
## (current master)
|
||||
- All new development should target Julia 0.7!
|
||||
|
||||
## 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
|
||||
@@ -112,7 +283,7 @@
|
||||
- add `reset_defaults()` function to reset plot defaults
|
||||
- update syntax to 0.6
|
||||
- make `fill = true` fill to 0 rather than to 1
|
||||
- use new `@df` syntax in StatPlots examples
|
||||
- use new `@df` syntax in StatsPlots examples
|
||||
- allow changing the color of legend box
|
||||
- implement `title_location` for gr
|
||||
- add `hline` marker to pgfplots - fixes errorbars
|
||||
@@ -264,7 +435,7 @@
|
||||
- added dependency on PlotThemes
|
||||
- set_theme --> theme
|
||||
- remove Compat from REQUIRE
|
||||
- warning for DataFrames without StatPlots
|
||||
- warning for DataFrames without StatsPlots
|
||||
- closeall exported and implemented for gr/pyplot
|
||||
- fix DateTime recipe
|
||||
- reset theme with theme(:none)
|
||||
@@ -386,8 +557,8 @@
|
||||
#### 0.8.0
|
||||
|
||||
- added dependency on PlotUtils
|
||||
- BREAKING: removed DataFrames support (now in StatPlots.jl)
|
||||
- BREAKING: removed boxplot/violin/density recipes (now in StatPlots.jl)
|
||||
- BREAKING: removed DataFrames support (now in StatsPlots.jl)
|
||||
- BREAKING: removed boxplot/violin/density recipes (now in StatsPlots.jl)
|
||||
- GR:
|
||||
- inline iterm2 support
|
||||
- trisurface support
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
name = "Plots"
|
||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
author = ["Tom Breloff (@tbreloff)"]
|
||||
version = "1.18.2"
|
||||
|
||||
[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.53, 0.54, 0.55, 0.57"
|
||||
GeometryBasics = "0.2, 0.3.1"
|
||||
JSON = "0.21, 1"
|
||||
Latexify = "0.14, 0.15"
|
||||
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, 1.0"
|
||||
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"
|
||||
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
|
||||
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", "PlotlyJS", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]
|
||||
@@ -1,16 +1,30 @@
|
||||
# Plots
|
||||
|
||||
[](https://travis-ci.org/JuliaPlots/Plots.jl)
|
||||
[](https://ci.appveyor.com/project/mkborregaard/plots-jl)
|
||||
[](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
|
||||
<!-- [](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
|
||||
<!-- [](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
|
||||
[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
|
||||
|
||||
[pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/P/Plots.svg
|
||||
[pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html
|
||||
|
||||
[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
|
||||
|
||||
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
|
||||
[docs-url]: http://docs.juliaplots.org/latest/
|
||||
|
||||
[![][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)
|
||||
|
||||
[](https://doi.org/10.5281/zenodo.4725317)
|
||||
This is the DOI for all Versions, please follow the link to get the DOI for a specific version.
|
||||
|
||||
|
||||
#### Created by Tom Breloff (@tbreloff)
|
||||
|
||||
#### Maintained by the [JuliaPlot members](https://github.com/orgs/JuliaPlots/people)
|
||||
#### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people)
|
||||
|
||||
Plots is a plotting API and toolset. My goals with the package are:
|
||||
|
||||
@@ -21,5 +35,3 @@ Plots is a plotting API and toolset. My goals with the package are:
|
||||
- **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.
|
||||
|
||||
View the [full documentation](http://docs.juliaplots.org/latest).
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
julia 0.6
|
||||
|
||||
RecipesBase 0.2.3
|
||||
PlotUtils 0.4.1
|
||||
PlotThemes 0.1.3
|
||||
Reexport
|
||||
StaticArrays 0.5
|
||||
FixedPointNumbers 0.3
|
||||
Measures
|
||||
Showoff
|
||||
StatsBase 0.14.0
|
||||
JSON
|
||||
NaNMath
|
||||
Requires
|
||||
Contour
|
||||
GR 0.31.0
|
||||
@@ -1,39 +0,0 @@
|
||||
environment:
|
||||
matrix:
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" #check and address
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
on_build_failure: false
|
||||
on_build_status_changed: false
|
||||
|
||||
install:
|
||||
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
|
||||
# If there's a newer build queued for the same PR, cancel this one
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
# Download most recent Julia Windows binary
|
||||
- ps: (new-object net.webclient).DownloadFile($env:JULIA_URL, "C:\projects\julia-binary.exe")
|
||||
# Run installer silently, output to C:\projects\julia
|
||||
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
|
||||
|
||||
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 -e "Pkg.test(\"Plots\")"
|
||||
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"
|
||||
@@ -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
|
||||
+10
@@ -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"
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
# Use
|
||||
# @warnpcfail precompile(args...)
|
||||
# if you want to be warned when a precompile directive fails
|
||||
macro warnpcfail(ex::Expr)
|
||||
modl = __module__
|
||||
file = __source__.file === nothing ? "?" : String(__source__.file)
|
||||
line = __source__.line
|
||||
quote
|
||||
$(esc(ex)) || @warn """precompile directive
|
||||
$($(Expr(:quote, ex)))
|
||||
failed. Please report an issue in $($modl) (after checking for duplicates) or remove this directive.""" _file=$file _line=$line
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
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, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Int64})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Tuple{Int64, Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Vector{Int64}}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
|
||||
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, :flip, :minorgrid, :guide), Tuple{Bool, Bool, Bool, String}},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, :minorgrid, :guide), Tuple{Bool, Bool, String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :minorgrid, :mirror, :guide), Tuple{Bool, Bool, Bool, String}},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{(:guide_position, :guidefontvalign, :mirror, :guide), Tuple{Symbol, Symbol, Bool, String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guidefonthalign, :guide_position, :mirror, :guide), Tuple{Symbol, Symbol, Bool, 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{(:minorgrid, :scale, :guide), Tuple{Bool, Symbol, String}},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{(: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{(:shape,), Tuple{Symbol}},typeof(default)})
|
||||
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(font)),NamedTuple{(:family, :pointsize, :halign, :valign, :rotation, :color), Tuple{String, Int64, Symbol, Symbol, Float64, RGBA{Float64}}},typeof(font)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(font)),NamedTuple{(:family, :pointsize, :valign, :halign, :rotation, :color), Tuple{String, Int64, Symbol, Symbol, Float64, RGBA{Float64}}},typeof(font)})
|
||||
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}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),StepRange{Int64, Int64},Vector{Float64}})
|
||||
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(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),UnitRange{Int64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),Vector{Int64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(hline!)),Any,typeof(hline!),Any})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Plot{GRBackend},Vector{GeometryBasics.Point2{Float64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{GeometryBasics.Point2{Float64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Vector{GeometryBasics.Point2{Float64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:annotation,), Tuple{Vector{Tuple{Int64, Float64, PlotText}}}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{GridLayout, AbsoluteLength}},typeof(plot!),Plot{GRBackend},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},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},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{GRBackend},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},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype), Tuple{Tuple{Int64, Symbol, Float64, Matrix{Symbol}}, Symbol}},typeof(plot!),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype), Tuple{Tuple{Int64, Symbol, Float64, Matrix{Symbol}}, Symbol}},typeof(plot!),Plot{GRBackend},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype), Tuple{Tuple{Int64, Symbol, Float64, Matrix{Symbol}}, Symbol}},typeof(plot!),Plot{PlotlyBackend},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Function,Float64,Irrational{:π}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Plot{GRBackend},Function,Float64,Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),Plot{GRBackend},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),Plot{PlotlyBackend},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Vector{Float64}})
|
||||
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},Vector{Int64},Vector{Float64}})
|
||||
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},Vector{Int64},Vector{Float64}})
|
||||
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!),Vector{Int64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot!),Plot{GRBackend},Vector{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot!),Vector{Int64}})
|
||||
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{(:title,), Tuple{String}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:w,), Tuple{Int64}},typeof(plot!),Plot{GRBackend},Vector{Float64},Vector{Float64},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, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!),Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!),Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:annotations, :leg), Tuple{Tuple{Int64, Float64, PlotText}, Bool}},typeof(plot),Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:arrow,), Tuple{Int64}},typeof(plot),Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:aspect_ratio, :seriestype), Tuple{Int64, Symbol}},typeof(plot),Vector{String},Vector{String},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:bins, :weights, :seriestype), Tuple{Symbol, Vector{Int64}, Symbol}},typeof(plot),Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:color, :line, :marker), Tuple{Matrix{Symbol}, Tuple{Symbol, Int64}, Tuple{Matrix{Symbol}, Int64, Float64, Stroke}}},typeof(plot),Vector{Vector{T} where T}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:connections, :seriestype), Tuple{Tuple{Vector{Int64}, Vector{Int64}, Vector{Int64}}, Symbol}},typeof(plot),Vector{Int64},Vector{Int64},Vector{Int64}})
|
||||
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}},Function})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:framestyle, :title, :color, :layout, :label, :markerstrokewidth, :ticks, :seriestype), Tuple{Matrix{Symbol}, Matrix{String}, Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}}, Int64, String, Int64, UnitRange{Int64}, Symbol}},typeof(plot),Vector{Vector{Float64}},Vector{Vector{Float64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:grid, :title), Tuple{Tuple{Symbol, Symbol, Symbol, Int64, Float64}, String}},typeof(plot),Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:lab, :w, :palette, :fill, :α), Tuple{String, Int64, PlotUtils.ContinuousColorGradient, Int64, Float64}},typeof(plot),StepRange{Int64, Int64},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label, :title, :xlabel, :linewidth, :legend), Tuple{Matrix{String}, String, String, Int64, Symbol}},typeof(plot),Vector{Function},Float64,Float64})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label,), Tuple{Matrix{String}}},typeof(plot),Vector{AbstractVector{Float64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :group, :linetype, :linecolor), Tuple{GridLayout, Vector{String}, Matrix{Symbol}, Symbol}},typeof(plot),Vector{Float64}})
|
||||
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},Plot{GRBackend}})
|
||||
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},Plot{PlotlyBackend}})
|
||||
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, :margin), Tuple{GridLayout, AbsoluteLength}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :palette, :bg_inside), Tuple{Int64, Matrix{PlotUtils.ContinuousColorGradient}, Matrix{Symbol}}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :t, :leg, :ticks, :border), Tuple{GridLayout, Matrix{Symbol}, Bool, Nothing, Symbol}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :title, :titlelocation, :left_margin, :bottom_margin, :xrotation), Tuple{GridLayout, Matrix{String}, Symbol, Matrix{AbsoluteLength}, AbsoluteLength, Int64}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xguide, :yguide, :xguidefonthalign, :yguidefontvalign, :xguideposition, :yguideposition, :ymirror, :xmirror, :legend, :seriestype), Tuple{Int64, String, String, Matrix{Symbol}, Matrix{Symbol}, Symbol, Matrix{Symbol}, Matrix{Bool}, Matrix{Bool}, Bool, Matrix{Symbol}}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xlims), Tuple{GridLayout, Tuple{Int64, Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot),Plot{GRBackend},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},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Plot{GRBackend},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},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Vector{Tuple{Int64, Real}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :lab, :ms), Tuple{Tuple{Matrix{Symbol}, Int64}, Matrix{String}, Int64}},typeof(plot),Vector{Vector{T} where T},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :label, :legendtitle), Tuple{Tuple{Int64, Matrix{Symbol}}, Matrix{String}, String}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :leg, :fill), Tuple{Int64, Bool, Tuple{Int64, Symbol}}},typeof(plot),Function,Function,Int64,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{Float64, Float64}, Int64, RGBA{Float64}}, Symbol, Symbol, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Bool}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
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),Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:m, :markersize, :lab, :bg, :xlim, :ylim, :seriestype), Tuple{Matrix{Symbol}, Int64, Matrix{String}, Symbol, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:marker,), Tuple{Bool}},typeof(plot),Vector{Union{Missing, Int64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:marker_z, :color, :legend, :seriestype), Tuple{typeof(+), Symbol, Bool, Symbol}},typeof(plot),Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:markershape, :markersize, :marker_z, :line_z, :linewidth), Tuple{Matrix{Symbol}, Matrix{Int64}, Matrix{Int64}, Matrix{Int64}, Matrix{Int64}}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:markershape, :seriestype, :label), Tuple{Symbol, Symbol, String}},typeof(plot),UnitRange{Int64},Vector{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:nbins, :seriestype), Tuple{Int64, Symbol}},typeof(plot),Vector{Float64},Vector{Float64}})
|
||||
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),Vector{ComplexF64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:proj, :m), Tuple{Symbol, Int64}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:projection, :seriestype), Tuple{Symbol, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},UnitRange{Int64},Matrix{Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:quiver, :seriestype), Tuple{Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:reg, :fill), Tuple{Bool, Tuple{Int64, Symbol}}},typeof(plot),Vector{Float64}})
|
||||
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{Matrix{Symbol}, Vector{Symbol}, Int64, Vector{Symbol}}},typeof(plot),Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{DateTime},UnitRange{Int64},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{OHLC}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:st, :xlabel, :ylabel, :zlabel), Tuple{Symbol, String, String, String}},typeof(plot),Vector{Float64},Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :l, :seriestype), Tuple{String, Float64, Symbol}},typeof(plot),Vector{String},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xflip, :yflip, :zflip, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xmirror, :ymirror, :zmirror, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,), Tuple{Matrix{String}}},typeof(plot),Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,), Tuple{Matrix{String}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:w,), Tuple{Int64}},typeof(plot),Matrix{Float64}})
|
||||
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),Matrix{Float64}})
|
||||
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),Vector{Float64},Vector{Float64},UnitRange{Int64}})
|
||||
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})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(test_examples)),NamedTuple{(:skip, :disp), Tuple{Vector{Int64}, Bool}},typeof(test_examples),Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(test_examples)),NamedTuple{(:skip,), Tuple{Vector{Int64}}},typeof(test_examples),Symbol})
|
||||
Base.precompile(Tuple{Type{GridLayout},Int64,Vararg{Int64, N} where N})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},AbstractVector{OHLC}})
|
||||
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{:bins2d}},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{:lens}},AbstractPlot})
|
||||
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{:steppre}},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{:vline}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:xerror}},Any,Any,Any})
|
||||
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Vector{ComplexF64}})
|
||||
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},Vector{Dict{Symbol, Any}}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{PlotlyBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plot{GRBackend},DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{GRBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}},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),Vector{Int64},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Nothing},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{PlotUtils.ContinuousColorGradient},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Symbol},String})
|
||||
Base.precompile(Tuple{typeof(_cycle),Base.OneTo{Int64},Vector{Int64}})
|
||||
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},StepRange{Int64, Int64}})
|
||||
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),Vector{Float64},Bool,Bool})
|
||||
Base.precompile(Tuple{typeof(_plot!),Plot,Any,Any})
|
||||
Base.precompile(Tuple{typeof(_preprocess_barlike),DefaultsDict,Base.OneTo{Int64},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(_preprocess_binlike),DefaultsDict,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
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(_update_subplot_periphery),Subplot{GRBackend},Vector{Any}})
|
||||
Base.precompile(Tuple{typeof(_update_subplot_periphery),Subplot{PlotlyBackend},Vector{Any}})
|
||||
Base.precompile(Tuple{typeof(axis_limits),Subplot{GRBackend},Symbol,Bool,Bool})
|
||||
Base.precompile(Tuple{typeof(axis_limits),Subplot{PlotlyBackend},Symbol,Bool,Bool})
|
||||
Base.precompile(Tuple{typeof(backend),PlotlyBackend})
|
||||
Base.precompile(Tuple{typeof(bbox),AbsoluteLength,AbsoluteLength,AbsoluteLength,AbsoluteLength})
|
||||
Base.precompile(Tuple{typeof(bbox),Float64,Float64,Float64,Float64})
|
||||
Base.precompile(Tuple{typeof(build_layout),GridLayout,Int64,Vector{Plot}})
|
||||
Base.precompile(Tuple{typeof(convert_to_polar),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64},Tuple{Int64, Float64}})
|
||||
Base.precompile(Tuple{typeof(create_grid),Expr})
|
||||
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64},Vararg{Vector{Float64}, N} where N})
|
||||
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(error_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
|
||||
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Vector{Float64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Vector{Int64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{GRBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{PlotlyBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_ticks),StepRange{Int64, Int64},Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Float64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_ticks),UnitRange{Int64},Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_xy),OHLC{Float64},Int64,Float64})
|
||||
Base.precompile(Tuple{typeof(get_xy),Vector{OHLC}})
|
||||
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), NTuple{9, Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), Tuple{Int64, Int64, Int64, Float64, Int64, Float64, Float64, Float64, Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_display),Subplot{GRBackend},AbsoluteLength,AbsoluteLength,Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_colorbar),GRColorbar,Subplot{GRBackend},Tuple{Float64, Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_contour),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_heatmap),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Float64,Float64,Symbol})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Shape{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Float64,Tuple{Float64, Float64},Int64,Float64,Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Int64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Base.OneTo{Int64},Vector{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},UnitRange{Int64},Tuple{Vector{Float64}, Vector{Float64}},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,StepRange{Int64, Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Vector{Float64},Vector{Float64},Int64,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_shapes),Series,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Vector{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_fill_viewport),Vector{Float64},RGBA{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Float64}, Vector{String}},Int64})
|
||||
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Int64}, Vector{String}},Int64})
|
||||
Base.precompile(Tuple{typeof(gr_label_ticks),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(gr_label_ticks),Subplot{GRBackend},Symbol,Tuple{Vector{Int64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(gr_label_ticks_3d),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(gr_polaraxes),Int64,Float64,Subplot{GRBackend}})
|
||||
Base.precompile(Tuple{typeof(gr_set_gradient),PlotUtils.ContinuousColorGradient})
|
||||
Base.precompile(Tuple{typeof(gr_update_viewport_legend!),Vector{Float64},Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), NTuple{9, Float64}}})
|
||||
Base.precompile(Tuple{typeof(gr_update_viewport_legend!),Vector{Float64},Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), Tuple{Int64, Int64, Int64, Float64, Int64, Float64, Float64, Float64, Float64}}})
|
||||
Base.precompile(Tuple{typeof(gr_viewport_from_bbox),Subplot{GRBackend},BoundingBox{Tuple{AbsoluteLength, AbsoluteLength}, Tuple{AbsoluteLength, AbsoluteLength}},AbsoluteLength,AbsoluteLength,Vector{Float64}})
|
||||
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,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol,Tuple{Int64, Int64},Bool})
|
||||
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(heatmap_edges),Vector{Float64},Symbol,UnitRange{Int64},Symbol,Tuple{Int64, Int64},Bool})
|
||||
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol,Vector{Float64},Symbol,Tuple{Int64, Int64},Bool})
|
||||
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol})
|
||||
Base.precompile(Tuple{typeof(ignorenan_minimum),Vector{Int64}})
|
||||
Base.precompile(Tuple{typeof(isvertical),Dict{Symbol, Any}})
|
||||
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),Nothing,Tuple{Float64, Float64},Symbol,Function})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Float64, Float64},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Int64, Float64},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Int64, Int64},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),StepRange{Int64, Int64},Tuple{Int64, Int64},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),UnitRange{Int64},Tuple{Float64, Float64},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(partialcircle),Int64,Float64,Int64})
|
||||
Base.precompile(Tuple{typeof(plot),Any,Any})
|
||||
Base.precompile(Tuple{typeof(plot),Any})
|
||||
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
|
||||
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
|
||||
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol, Any},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Matrix{Symbol}})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Matrix{Symbol}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},RGBA{Float64}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Shape{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Stroke})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(processMinorGridArg!),Dict{Symbol, Any},Bool,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},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(push!),Plot{GRBackend},Float64,Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(resetfontsizes)})
|
||||
Base.precompile(Tuple{typeof(scalefontsizes),Float64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{AbsoluteLength},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{Int64},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{PlotUtils.ContinuousColorGradient},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{RGBA{Float64}},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{String},Int64})
|
||||
Base.precompile(Tuple{typeof(spy),Any})
|
||||
Base.precompile(Tuple{typeof(straightline_data),Tuple{Float64, Float64},Tuple{Float64, Float64},Vector{Float64},Vector{Float64},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(title!),AbstractString})
|
||||
Base.precompile(Tuple{typeof(unzip),Vector{GeometryBasics.Point2{Float64}}})
|
||||
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}})
|
||||
isdefined(Plots, Symbol("#add_major_or_minor_segments#126")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#126")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
|
||||
isdefined(Plots, Symbol("#add_major_or_minor_segments#127")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#127")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
|
||||
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(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
|
||||
end
|
||||
+4
@@ -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)
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
using CompileBot
|
||||
|
||||
snoop_bench(
|
||||
BotConfig(
|
||||
"Plots",
|
||||
),
|
||||
joinpath(@__DIR__, "precompile_script.jl"),
|
||||
)
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
using CompileBot
|
||||
|
||||
snoop_bot(
|
||||
BotConfig(
|
||||
"Plots",
|
||||
),
|
||||
joinpath(@__DIR__, "precompile_script.jl"),
|
||||
)
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
|
||||
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
|
||||
|
||||
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
|
||||
if !isfile(local_fn)
|
||||
info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
|
||||
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
|
||||
end
|
||||
@@ -1,4 +0,0 @@
|
||||
git checkout master
|
||||
git merge --ff-only dev
|
||||
git push origin master
|
||||
git checkout dev
|
||||
+81
-136
@@ -1,14 +1,21 @@
|
||||
__precompile__(true)
|
||||
|
||||
module Plots
|
||||
|
||||
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 StaticArrays
|
||||
using StaticArrays.FixedSizeArrays
|
||||
import GeometryBasics
|
||||
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
|
||||
using SparseArrays
|
||||
|
||||
using FFMPEG
|
||||
|
||||
@reexport using RecipesBase
|
||||
import RecipesBase: plot, plot!, animate
|
||||
import RecipesBase: plot, plot!, animate, is_explicit
|
||||
using Base.Meta
|
||||
@reexport using PlotUtils
|
||||
@reexport using PlotThemes
|
||||
@@ -72,7 +79,6 @@ export
|
||||
backends,
|
||||
backend_name,
|
||||
backend_object,
|
||||
add_backend,
|
||||
aliases,
|
||||
|
||||
Shape,
|
||||
@@ -91,6 +97,7 @@ export
|
||||
gif,
|
||||
mov,
|
||||
mp4,
|
||||
webm,
|
||||
animate,
|
||||
@animate,
|
||||
@gif,
|
||||
@@ -104,11 +111,13 @@ export
|
||||
rotate,
|
||||
rotate!,
|
||||
center,
|
||||
P2,
|
||||
P3,
|
||||
BezierCurve,
|
||||
|
||||
plotattr
|
||||
plotattr,
|
||||
scalefontsize,
|
||||
scalefontsizes,
|
||||
resetfontsizes
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -118,7 +127,7 @@ 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) = Base.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)
|
||||
|
||||
@@ -145,6 +154,12 @@ 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
|
||||
|
||||
@@ -152,15 +167,39 @@ 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("components.jl")
|
||||
include("colorbars.jl")
|
||||
include("axes.jl")
|
||||
include("args.jl")
|
||||
include("components.jl")
|
||||
include("themes.jl")
|
||||
include("plot.jl")
|
||||
include("pipeline.jl")
|
||||
include("series.jl")
|
||||
include("layouts.jl")
|
||||
include("subplots.jl")
|
||||
include("recipes.jl")
|
||||
@@ -170,123 +209,41 @@ include("arg_desc.jl")
|
||||
include("plotattr.jl")
|
||||
include("backends.jl")
|
||||
include("output.jl")
|
||||
include("ijulia.jl")
|
||||
include("fileio.jl")
|
||||
include("init.jl")
|
||||
include("legend.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
include("backends/plotly.jl")
|
||||
include("backends/gr.jl")
|
||||
include("backends/web.jl")
|
||||
|
||||
@shorthands scatter
|
||||
@shorthands bar
|
||||
@shorthands barh
|
||||
@shorthands histogram
|
||||
@shorthands barhist
|
||||
@shorthands stephist
|
||||
@shorthands scatterhist
|
||||
@shorthands histogram2d
|
||||
@shorthands density
|
||||
@shorthands heatmap
|
||||
@shorthands plots_heatmap
|
||||
@shorthands hexbin
|
||||
@shorthands sticks
|
||||
@shorthands hline
|
||||
@shorthands vline
|
||||
@shorthands hspan
|
||||
@shorthands vspan
|
||||
@shorthands ohlc
|
||||
@shorthands contour
|
||||
@shorthands contourf
|
||||
@shorthands contour3d
|
||||
@shorthands surface
|
||||
@shorthands wireframe
|
||||
@shorthands path3d
|
||||
@shorthands scatter3d
|
||||
@shorthands boxplot
|
||||
@shorthands violin
|
||||
@shorthands quiver
|
||||
@shorthands curves
|
||||
|
||||
"Plot a pie diagram"
|
||||
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
|
||||
"Plot with seriestype :path3d"
|
||||
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
|
||||
"Add title to an existing plot"
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
|
||||
"Add xlabel to an existing plot"
|
||||
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
|
||||
|
||||
"Add ylabel to an existing plot"
|
||||
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
|
||||
|
||||
"Set xlims for an existing plot"
|
||||
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
|
||||
|
||||
"Set ylims for an existing plot"
|
||||
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
|
||||
|
||||
"Set zlims for an existing plot"
|
||||
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
|
||||
|
||||
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
|
||||
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
|
||||
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
|
||||
|
||||
|
||||
"Set xticks for an existing plot"
|
||||
xticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
|
||||
|
||||
"Set yticks for an existing plot"
|
||||
yticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
|
||||
|
||||
xticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
|
||||
yticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
|
||||
|
||||
"Add annotations to an existing plot"
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
|
||||
|
||||
"Flip the current plots' x axis"
|
||||
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
|
||||
|
||||
"Flip the current plots' y axis"
|
||||
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
|
||||
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
|
||||
include("shorthands.jl")
|
||||
|
||||
let PlotOrSubplot = Union{Plot, Subplot}
|
||||
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
|
||||
ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
|
||||
xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
|
||||
ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
|
||||
zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
|
||||
xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
|
||||
ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
|
||||
zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
|
||||
xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
|
||||
yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
|
||||
xticks!(plt::PlotOrSubplot,
|
||||
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...)
|
||||
yticks!(plt::PlotOrSubplot,
|
||||
global yticks!(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
|
||||
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
|
||||
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
|
||||
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
|
||||
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
|
||||
yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
|
||||
xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
|
||||
yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, 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
|
||||
|
||||
|
||||
@@ -294,18 +251,6 @@ end
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
# for compatibility with Requires.jl:
|
||||
@init begin
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
if haskey(Main.PLOTS_DEFAULTS, :theme)
|
||||
theme(Main.PLOTS_DEFAULTS[:theme])
|
||||
end
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
k == :theme || default(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
include("precompile_includer.jl")
|
||||
|
||||
end # module
|
||||
|
||||
+52
-24
@@ -24,6 +24,7 @@ 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
|
||||
@@ -60,57 +61,84 @@ end
|
||||
|
||||
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
|
||||
|
||||
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...)
|
||||
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
|
||||
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
|
||||
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(animdir::AbstractString, fn::AbstractString,
|
||||
function buildanimation(anim::Animation, fn::AbstractString,
|
||||
is_animated_gif::Bool=true;
|
||||
fps::Integer = 20, loop::Integer = 0,
|
||||
fps::Real = 20, loop::Integer = 0,
|
||||
variable_palette::Bool=false,
|
||||
verbose=false,
|
||||
show_msg::Bool=true)
|
||||
fn = abspath(fn)
|
||||
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"
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`)
|
||||
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
|
||||
run(`ffmpeg -v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
|
||||
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
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`)
|
||||
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
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
|
||||
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)
|
||||
show_msg && @info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
|
||||
# write out html to view the gif
|
||||
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
ext = file_extension(agif.filename)
|
||||
write(io, if ext == "gif"
|
||||
"<img src=\"$(relpath(agif.filename))?$(rand())>\" />"
|
||||
elseif ext in ("mov", "mp4")
|
||||
"<video controls><source src=\"$(relpath(agif.filename))?$(rand())>\" type=\"video/$ext\"></video>"
|
||||
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)
|
||||
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)")
|
||||
if forloop.head ∉ (:for, :while)
|
||||
error("@animate macro expects a for- or while-block. got: $(forloop.head)")
|
||||
end
|
||||
|
||||
# add the call to frame to the end of each iteration
|
||||
@@ -141,17 +169,17 @@ function _animate(forloop::Expr, args...; callgif = false)
|
||||
error("Unsupported animate filter: $args")
|
||||
end
|
||||
|
||||
push!(block.args, :(if $filterexpr; frame($animsym); end))
|
||||
push!(block.args, :($countersym += 1))
|
||||
push!(block.args, :(if $filterexpr; Plots.frame($animsym); end))
|
||||
push!(block.args, :(global $countersym += 1))
|
||||
|
||||
# add a final call to `gif(anim)`?
|
||||
retval = callgif ? :(gif($animsym)) : animsym
|
||||
retval = callgif ? :(Plots.gif($animsym)) : animsym
|
||||
|
||||
# full expression:
|
||||
esc(quote
|
||||
$freqassert # if filtering, check frequency is an Integer > 0
|
||||
$animsym = Animation() # init animation object
|
||||
$countersym = 1 # init iteration counter
|
||||
$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)
|
||||
|
||||
+175
-134
@@ -2,144 +2,185 @@
|
||||
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 from this to 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. `linspace(extrema(x)..., 25)`",
|
||||
:smooth => "Bool. Add a regression line?",
|
||||
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
|
||||
:x => "Various. Input data. First Dimension",
|
||||
: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 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 nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
|
||||
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
|
||||
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
|
||||
: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.",
|
||||
: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.",
|
||||
: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 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.",
|
||||
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
|
||||
:dpi => "Number. Dots Per Inch of output figures",
|
||||
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
|
||||
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
|
||||
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
|
||||
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
|
||||
: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.",
|
||||
:title_location => "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 Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
|
||||
:legendfontfamily => "String or Symbol. Font family of legend entries.",
|
||||
:legendfontsize => "Integer. Font pointsize of legend entries.",
|
||||
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
|
||||
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
|
||||
:legendfontrotation => "Real. Font rotation of legend entries",
|
||||
:legendfontcolor => "Color Type. Font color of legend entries",
|
||||
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
|
||||
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
|
||||
:legendfont => "Font. Font of legend items.",
|
||||
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
|
||||
:projection => "Symbol or String. '3d' or 'polar'",
|
||||
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
|
||||
: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",
|
||||
: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) or angle or (angle,inout) tuple. 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). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.",
|
||||
: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.",
|
||||
:colorbar_fontfamily => "String or Symbol. Font family of colobar entries.",
|
||||
:colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
|
||||
:colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.",
|
||||
:colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.",
|
||||
:colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries",
|
||||
:colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`",
|
||||
:colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
|
||||
: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, PlotText (created with `text(args...)`), or a tuple of arguments to `text` (e.g., `(\"Label\", 8, :red, :top)`). Add one-off text annotations at the x,y coordinates.",
|
||||
:annotationfontfamily => "String or Symbol. Font family of annotations.",
|
||||
:annotationfontsize => "Integer. Font pointsize of annotations.",
|
||||
:annotationhalign => "Symbol. horizontal alignment of annotations, :hcenter, :left, :right or :center.",
|
||||
:annotationvalign => "Symbol. Vertical alignment of annotations, :vcenter, :top, :bottom or :center.",
|
||||
:annotationrotation => "Float. Rotation of annotations in degrees.",
|
||||
:annotationcolor => "Colorant or :match. Color of annotations.",
|
||||
: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).",
|
||||
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
|
||||
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
|
||||
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
|
||||
:rotation => "Number. Degrees rotation of tick labels.",
|
||||
:flip => "Bool. Should we flip (reverse) the axis?",
|
||||
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
|
||||
: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)",
|
||||
: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`.",
|
||||
: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]
|
||||
`:symmetric` sets the limits to be symmetric around zero.
|
||||
Set widen=true to widen the specified limits (as occurs when lims are not specified).
|
||||
""",
|
||||
: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`, `:out` or `:none`",
|
||||
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
|
||||
:widen => """
|
||||
Bool or :auto. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders.
|
||||
Defaults to `:auto`, which widens unless limits were manually set.
|
||||
""",
|
||||
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
|
||||
)
|
||||
|
||||
+851
-590
File diff suppressed because it is too large
Load Diff
+535
-269
File diff suppressed because it is too large
Load Diff
+724
-84
@@ -1,46 +1,48 @@
|
||||
|
||||
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
|
||||
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported 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)
|
||||
str = lowercase(string(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(; kw...); backend(Symbol($str)))
|
||||
$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)
|
||||
include("backends/" * $str * ".jl")
|
||||
_backend_packages[Symbol($str)] = Symbol($package_str)
|
||||
end)
|
||||
end
|
||||
|
||||
include("backends/web.jl")
|
||||
# include("backends/web.jl")
|
||||
# include("backends/supported.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function add_backend(pkg::Symbol)
|
||||
info("To do a standard install of $pkg, copy and run this:\n\n")
|
||||
println(add_backend_string(_backend_instance(pkg)))
|
||||
println()
|
||||
end
|
||||
add_backend_string(b::AbstractBackend) = warn("No custom install defined for $(backend_name(b))")
|
||||
|
||||
# don't do anything as a default
|
||||
_create_backend_figure(plt::Plot) = nothing
|
||||
_prepare_plot_object(plt::Plot) = nothing
|
||||
@@ -70,9 +72,9 @@ end
|
||||
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
|
||||
|
||||
# account for the size/length/rotation of tick labels
|
||||
function tick_padding(axis::Axis)
|
||||
ticks = get_ticks(axis)
|
||||
if ticks == nothing
|
||||
function tick_padding(sp::Subplot, axis::Axis)
|
||||
ticks = get_ticks(sp, axis)
|
||||
if ticks === nothing
|
||||
0mm
|
||||
else
|
||||
vals, labs = ticks
|
||||
@@ -100,11 +102,11 @@ 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 `is3d(sp) == true`
|
||||
leftpad = tick_padding(sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
|
||||
# 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[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
|
||||
bottompad = tick_padding(sp, sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
|
||||
|
||||
# switch them?
|
||||
if sp[:xaxis][:mirror]
|
||||
@@ -131,34 +133,22 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function pickDefaultBackend()
|
||||
_fallback_default_backend() = backend(GRBackend())
|
||||
|
||||
function _pick_default_backend()
|
||||
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
|
||||
if env_default != ""
|
||||
try
|
||||
Pkg.installed(env_default) # this will error if not installed
|
||||
sym = Symbol(lowercase(env_default))
|
||||
if haskey(_backendType, sym)
|
||||
return 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"))
|
||||
end
|
||||
catch
|
||||
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not installed.")
|
||||
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
|
||||
|
||||
# the ordering/inclusion of this package list is my semi-arbitrary guess at
|
||||
# which one someone will want to use if they have the package installed...accounting for
|
||||
# features, speed, and robustness
|
||||
for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
|
||||
if Pkg.installed(pkgstr) != nothing
|
||||
return backend(Symbol(lowercase(pkgstr)))
|
||||
end
|
||||
end
|
||||
|
||||
# the default if nothing else is installed
|
||||
backend(:plotly)
|
||||
end
|
||||
|
||||
|
||||
@@ -168,55 +158,45 @@ end
|
||||
Returns the current plotting package name. Initializes package on first call.
|
||||
"""
|
||||
function backend()
|
||||
|
||||
global CURRENT_BACKEND
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
end
|
||||
|
||||
sym = CURRENT_BACKEND.sym
|
||||
if !(sym in _initialized_backends)
|
||||
|
||||
# # initialize
|
||||
# println("[Plots.jl] Initializing backend: ", sym)
|
||||
|
||||
inst = _backend_instance(sym)
|
||||
try
|
||||
_initialize_backend(inst)
|
||||
catch err
|
||||
warn("Couldn't initialize $sym. (might need to install it?)")
|
||||
add_backend(sym)
|
||||
rethrow(err)
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
_pick_default_backend()
|
||||
end
|
||||
|
||||
push!(_initialized_backends, sym)
|
||||
|
||||
end
|
||||
CURRENT_BACKEND.pkg
|
||||
CURRENT_BACKEND.pkg
|
||||
end
|
||||
|
||||
"""
|
||||
Set the plot backend.
|
||||
"""
|
||||
function backend(pkg::AbstractBackend)
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
warn_on_deprecated_backend(CURRENT_BACKEND.sym)
|
||||
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
|
||||
backend()
|
||||
pkg
|
||||
end
|
||||
|
||||
function backend(modname::Symbol)
|
||||
warn_on_deprecated_backend(modname)
|
||||
CURRENT_BACKEND.sym = modname
|
||||
CURRENT_BACKEND.pkg = _backend_instance(modname)
|
||||
backend()
|
||||
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]
|
||||
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize, :pgfplots]
|
||||
|
||||
function warn_on_deprecated_backend(bsym::Symbol)
|
||||
if bsym in _deprecated_backends
|
||||
warn("Backend $bsym has been deprecated. It may not work as originally intended.")
|
||||
if bsym == :pgfplots
|
||||
@warn("Backend $bsym has been deprecated. Use pgfplotsx instead.")
|
||||
else
|
||||
@warn("Backend $bsym has been deprecated.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -233,7 +213,7 @@ const _base_supported_args = [
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:smooth,
|
||||
:xerror, :yerror,
|
||||
:xerror, :yerror, :zerror,
|
||||
:subplot,
|
||||
:x, :y, :z,
|
||||
:show, :size,
|
||||
@@ -250,7 +230,7 @@ const _base_supported_args = [
|
||||
:subplot_index,
|
||||
:discrete_values,
|
||||
:projection,
|
||||
|
||||
:show_empty_bins
|
||||
]
|
||||
|
||||
function merge_with_base_supported(v::AVec)
|
||||
@@ -267,20 +247,16 @@ end
|
||||
|
||||
|
||||
|
||||
# @init_backend Immerse
|
||||
# @init_backend Gadfly
|
||||
@init_backend PyPlot
|
||||
# @init_backend Qwt
|
||||
@init_backend UnicodePlots
|
||||
# @init_backend Winston
|
||||
# @init_backend Bokeh
|
||||
@init_backend Plotly
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend GLVisualize
|
||||
@init_backend PGFPlots
|
||||
@init_backend PGFPlotsX
|
||||
@init_backend InspectDR
|
||||
@init_backend HDF5
|
||||
@init_backend Gaston
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -308,3 +284,667 @@ 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,
|
||||
:mesh3d,
|
||||
: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,
|
||||
:colorbar_ticks, :colorbar_tickfontfamily, :colorbar_tickfontsize,
|
||||
:colorbar_tickfonthalign, :colorbar_tickfontvalign,
|
||||
:colorbar_tickfontrotation, :colorbar_tickfontcolor,
|
||||
:colorbar_scale,
|
||||
: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,
|
||||
:stepmid,
|
||||
: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]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Gaston
|
||||
|
||||
function _initialize_backend(::GastonBackend)
|
||||
@eval Main begin
|
||||
import Gaston
|
||||
export Gaston
|
||||
end
|
||||
end
|
||||
|
||||
const _gaston_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 _gaston_seriestype = [:path,
|
||||
# :path3d,
|
||||
:scatter,
|
||||
:steppre,
|
||||
# :stepmid,
|
||||
:steppost,
|
||||
# :histogram2d,
|
||||
# :ysticks, :xsticks,
|
||||
# :contour,
|
||||
:shape,
|
||||
# :straightline,
|
||||
]
|
||||
|
||||
const _gaston_style = [:auto,
|
||||
:solid,
|
||||
:dash,
|
||||
:dot,
|
||||
:dashdot,
|
||||
:dashdotdot
|
||||
]
|
||||
|
||||
const _gaston_marker = [:none,
|
||||
# :auto,
|
||||
:circle,
|
||||
:rect,
|
||||
:diamond,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:pentagon,
|
||||
:x,
|
||||
:+
|
||||
] #vcat(_allMarkers, Shape)
|
||||
|
||||
const _gaston_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,
|
||||
:stepmid,
|
||||
: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, :stepmid, :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,
|
||||
:x,
|
||||
: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()
|
||||
|
||||
@@ -2,68 +2,6 @@
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
@require Revise begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pgfplots.jl"))
|
||||
end
|
||||
|
||||
const _pgfplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
# :foreground_color_legend,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
# :bar_width, :bar_edges,
|
||||
:title,
|
||||
# :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
:colorbar,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
:tick_direction,
|
||||
:framestyle,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::PGFPlotsBackend)
|
||||
"""
|
||||
Pkg.add("PGFPlots")
|
||||
Pkg.build("PGFPlots")
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::PGFPlotsBackend; kw...)
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
const _pgfplots_linestyles = KW(
|
||||
@@ -88,7 +26,8 @@ const _pgfplots_markers = KW(
|
||||
:star6 => "asterisk",
|
||||
:diamond => "diamond*",
|
||||
:pentagon => "pentagon*",
|
||||
:hline => "-"
|
||||
:hline => "-",
|
||||
:vline => "|"
|
||||
)
|
||||
|
||||
const _pgfplots_legend_pos = KW(
|
||||
@@ -124,7 +63,7 @@ function pgf_framestyle(style::Symbol)
|
||||
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.")
|
||||
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
|
||||
default_style
|
||||
end
|
||||
end
|
||||
@@ -154,10 +93,10 @@ 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(d, i = 1)
|
||||
cstr,a = pgf_color(get_fillcolor(d, i))
|
||||
fa = get_fillalpha(d, i)
|
||||
if fa != nothing
|
||||
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"
|
||||
@@ -172,11 +111,11 @@ function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
|
||||
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
|
||||
end
|
||||
|
||||
function pgf_linestyle(d, i = 1)
|
||||
lw = pgf_thickness_scaling(d) * get_linewidth(d, i)
|
||||
lc = get_linecolor(d, i)
|
||||
la = get_linealpha(d, i)
|
||||
ls = get_linestyle(d, i)
|
||||
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
|
||||
|
||||
@@ -185,20 +124,22 @@ function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
|
||||
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
|
||||
end
|
||||
|
||||
function pgf_marker(d, i = 1)
|
||||
shape = _cycle(d[:markershape], i)
|
||||
cstr, a = pgf_color(plot_color(get_markercolor(d, i), get_markeralpha(d, i)))
|
||||
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(d, i), get_markerstrokealpha(d, i)))
|
||||
"""
|
||||
mark = $(get(_pgfplots_markers, shape, "*")),
|
||||
mark size = $(pgf_thickness_scaling(d) * 0.5 * _cycle(d[:markersize], i)),
|
||||
mark options = {
|
||||
color = $cstr_stroke, draw opacity = $a_stroke,
|
||||
fill = $cstr, fill opacity = $a,
|
||||
line width = $(pgf_thickness_scaling(d) * _cycle(d[:markerstrokewidth], i)),
|
||||
rotate = $(shape == :dtriangle ? 180 : 0),
|
||||
$(get(_pgfplots_linestyles, _cycle(d[:markerstrokestyle], i), "solid"))
|
||||
}"""
|
||||
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)
|
||||
@@ -218,38 +159,38 @@ end
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function pgf_series(sp::Subplot, series::Series)
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
plotattributes = series.plotattributes
|
||||
st = plotattributes[:seriestype]
|
||||
series_collection = PGFPlots.Plot[]
|
||||
|
||||
# function args
|
||||
args = if st == :contour
|
||||
d[:z].surf, d[:x], d[:y]
|
||||
elseif is3d(st)
|
||||
d[:x], d[:y], d[:z]
|
||||
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 = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
|
||||
theta, r = plotattributes[:x], plotattributes[:y]
|
||||
rad2deg.(theta), r
|
||||
else
|
||||
d[:x], d[:y]
|
||||
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)
|
||||
# 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(d))
|
||||
push!(style, pgf_marker(d))
|
||||
push!(style, pgf_linestyle(plotattributes))
|
||||
push!(style, pgf_marker(plotattributes))
|
||||
push!(style, "forget plot")
|
||||
|
||||
kw[:style] = join(style, ',')
|
||||
@@ -268,21 +209,21 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
for (i, rng) in enumerate(segments)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(d, i))
|
||||
push!(style, pgf_marker(d, i))
|
||||
push!(style, pgf_linestyle(plotattributes, i))
|
||||
push!(style, pgf_marker(plotattributes, i))
|
||||
|
||||
if st == :shape
|
||||
push!(style, pgf_fillstyle(d, i))
|
||||
push!(style, pgf_fillstyle(plotattributes, i))
|
||||
end
|
||||
|
||||
# add to legend?
|
||||
if i == 1 && sp[:legend] != :none && should_add_to_legend(series)
|
||||
if d[:fillrange] != nothing
|
||||
if plotattributes[:fillrange] !== nothing
|
||||
push!(style, "forget plot")
|
||||
push!(series_collection, pgf_fill_legend_hack(d, args))
|
||||
push!(series_collection, pgf_fill_legend_hack(plotattributes, args))
|
||||
else
|
||||
kw[:legendentry] = d[:label]
|
||||
if st == :shape # || d[:fillrange] != nothing
|
||||
kw[:legendentry] = plotattributes[:label]
|
||||
if st == :shape # || plotattributes[:fillrange] !== nothing
|
||||
push!(style, "area legend")
|
||||
end
|
||||
end
|
||||
@@ -299,7 +240,7 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
kw[:style] = join(style, ',')
|
||||
|
||||
# add fillrange
|
||||
if series[:fillrange] != nothing && st != :shape
|
||||
if series[:fillrange] !== nothing && st != :shape
|
||||
push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...))
|
||||
end
|
||||
|
||||
@@ -330,7 +271,7 @@ function pgf_fillrange_series(series, i, fillrange, args...)
|
||||
push!(style, _pgf_series_extrastyle[st])
|
||||
end
|
||||
kw[:style] = join(style, ',')
|
||||
func = is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear
|
||||
func = RecipesPipeline.is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear
|
||||
return func(pgf_fillrange_args(fillrange, args...)...; kw...)
|
||||
end
|
||||
|
||||
@@ -349,16 +290,16 @@ function pgf_fillrange_args(fillrange, x, y, z)
|
||||
return x_fill, y_fill, z_fill
|
||||
end
|
||||
|
||||
function pgf_fill_legend_hack(d, args)
|
||||
function pgf_fill_legend_hack(plotattributes, args)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(d, 1))
|
||||
push!(style, pgf_marker(d, 1))
|
||||
push!(style, pgf_fillstyle(d, 1))
|
||||
push!(style, pgf_linestyle(plotattributes, 1))
|
||||
push!(style, pgf_marker(plotattributes, 1))
|
||||
push!(style, pgf_fillstyle(plotattributes, 1))
|
||||
push!(style, "area legend")
|
||||
kw[:legendentry] = d[:label]
|
||||
kw[:legendentry] = plotattributes[:label]
|
||||
kw[:style] = join(style, ',')
|
||||
st = d[:seriestype]
|
||||
st = plotattributes[:seriestype]
|
||||
func = if st == :path3d
|
||||
PGFPlots.Linear3
|
||||
elseif st == :scatter
|
||||
@@ -385,9 +326,17 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# axis guide
|
||||
kw[Symbol(letter,:label)] = axis[:guide]
|
||||
|
||||
# axis label position
|
||||
labelpos = ""
|
||||
if letter == :x && axis[:guide_position] == :top
|
||||
labelpos = "at={(0.5,1)},above,"
|
||||
elseif letter == :y && axis[:guide_position] == :right
|
||||
labelpos = "at={(1,0.5)},below,"
|
||||
end
|
||||
|
||||
# Add label font
|
||||
cstr, α = pgf_color(plot_color(axis[:guidefontcolor]))
|
||||
push!(style, string(letter, "label style = {font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}"))
|
||||
push!(style, string(letter, "label style = {", labelpos ,"font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}"))
|
||||
|
||||
# flip/reverse?
|
||||
axis[:flip] && push!(style, "$letter dir=reverse")
|
||||
@@ -414,29 +363,30 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# limits
|
||||
# TODO: support zlims
|
||||
if letter != :z
|
||||
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
|
||||
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||
ticks = get_ticks(axis)
|
||||
ticks = get_ticks(sp, axis)
|
||||
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
|
||||
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
|
||||
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
|
||||
# wrap the power part of label with }
|
||||
tick_labels = String[begin
|
||||
tick_labels = Vector{String}(undef, length(ticks[2]))
|
||||
for (i, label) in enumerate(ticks[2])
|
||||
base, power = split(label, "^")
|
||||
power = string("{", power, "}")
|
||||
string(base, "^", power)
|
||||
end for label in ticks[2]]
|
||||
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, "×", "\\times")
|
||||
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
|
||||
end
|
||||
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
|
||||
else
|
||||
@@ -451,14 +401,18 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# framestyle
|
||||
if framestyle in (:axes, :origin)
|
||||
axispos = framestyle == :axes ? "left" : "middle"
|
||||
# the * after lines disables the arrows at the axes
|
||||
push!(style, string("axis lines* = ", axispos))
|
||||
if axis[:draw_arrow]
|
||||
push!(style, string("axis ", letter, " line = ", axispos))
|
||||
else
|
||||
# the * after line disables the arrow at the axis
|
||||
push!(style, string("axis ", letter, " line* = ", axispos))
|
||||
end
|
||||
end
|
||||
|
||||
if framestyle == :zerolines
|
||||
push!(style, string("extra ", letter, " ticks = 0"))
|
||||
push!(style, string("extra ", letter, " tick labels = "))
|
||||
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
|
||||
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}"))
|
||||
end
|
||||
|
||||
if !axis[:showaxis]
|
||||
@@ -467,7 +421,7 @@ function pgf_axis(sp::Subplot, letter)
|
||||
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
|
||||
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
|
||||
else
|
||||
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}"))
|
||||
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}"))
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
@@ -490,7 +444,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
|
||||
# add to style/kw for each axis
|
||||
for letter in (:x, :y, :z)
|
||||
if letter != :z || is3d(sp)
|
||||
if letter != :z || RecipesPipeline.is3d(sp)
|
||||
axisstyle, axiskw = pgf_axis(sp, letter)
|
||||
append!(style, axisstyle)
|
||||
merge!(kw, axiskw)
|
||||
@@ -504,7 +458,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
bb = bbox(sp)
|
||||
push!(style, """
|
||||
xshift = $(left(bb).value)mm,
|
||||
yshift = $(round((total_height - (bottom(bb))).value,2))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"
|
||||
@@ -516,7 +470,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
|
||||
end
|
||||
|
||||
if sp[:aspect_ratio] in (1, :equal)
|
||||
if get_aspect_ratio(sp) in (1, :equal)
|
||||
kw[:axisEqual] = "true"
|
||||
end
|
||||
|
||||
@@ -524,13 +478,23 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
if haskey(_pgfplots_legend_pos, legpos)
|
||||
kw[:legendPos] = _pgfplots_legend_pos[legpos]
|
||||
end
|
||||
cstr, a = pgf_color(plot_color(sp[:background_color_legend]))
|
||||
push!(style, string("legend style = {", pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid"), ",", "fill = $cstr,", "font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), "}"))
|
||||
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 is3d(sp)
|
||||
elseif RecipesPipeline.is3d(sp)
|
||||
azim, elev = sp[:camera]
|
||||
kw[:view] = "{$(azim)}{$(elev)}"
|
||||
end
|
||||
@@ -555,8 +519,8 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
# colormap this should not cause any problem.
|
||||
for series in series_list(sp)
|
||||
for col in (:markercolor, :fillcolor, :linecolor)
|
||||
if typeof(series.d[col]) == ColorGradient
|
||||
push!(style,"colormap={plots}{$(pgf_colormap(series.d[col]))}")
|
||||
if typeof(series.plotattributes[col]) == ColorGradient
|
||||
push!(style,"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}")
|
||||
|
||||
if sp[:colorbar] == :none
|
||||
kw[:colorbar] = "false"
|
||||
@@ -570,11 +534,12 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
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!.(o, pgf_series(sp, series))
|
||||
push!.(Ref(o), pgf_series(sp, series))
|
||||
|
||||
# add series annotations
|
||||
anns = series[:series_annotations]
|
||||
@@ -607,7 +572,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
|
||||
|
||||
# read it into io
|
||||
write(io, readstring(open(fn)))
|
||||
write(io, read(open(fn), String))
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
@@ -615,8 +580,8 @@ end
|
||||
|
||||
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
|
||||
fn = tempname()*".tex"
|
||||
PGFPlots.save(fn, backend_object(plt), include_preamble=false)
|
||||
write(io, readstring(open(fn)))
|
||||
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})
|
||||
@@ -0,0 +1,331 @@
|
||||
# https://github.com/mbaz/Gaston.
|
||||
const G = Gaston
|
||||
const GastonSubplot = G.Plot
|
||||
const GASTON_MARKER_SCALING = 1.3 / 5.0
|
||||
const GNUPLOT_DPI = 72 # Compensate for DPI with increased resolution
|
||||
|
||||
#
|
||||
# --------------------------------------------
|
||||
# These functions are called by Plots
|
||||
# --------------------------------------------
|
||||
#
|
||||
# Create the window/figure for this backend.
|
||||
function _create_backend_figure(plt::Plot{GastonBackend})
|
||||
xsize = plt.attr[:size][1]
|
||||
ysize = plt.attr[:size][2]
|
||||
G.set(termopts="""size $xsize,$ysize""")
|
||||
|
||||
state_handle = G.nexthandle() # for now all the figures will be kept
|
||||
plt.o = G.newfigure(state_handle)
|
||||
end
|
||||
|
||||
|
||||
function _before_layout_calcs(plt::Plot{GastonBackend})
|
||||
# Initialize all the subplots first
|
||||
plt.o.subplots = G.SubPlot[]
|
||||
grid = size(plt.layout)
|
||||
plt.o.layout = grid
|
||||
|
||||
|
||||
for sp in plt.subplots
|
||||
gaston_init_subplot(plt, sp)
|
||||
end
|
||||
|
||||
# Then add the series (curves in gaston)
|
||||
for series in plt.series_list
|
||||
gaston_add_series(plt, series)
|
||||
end
|
||||
end
|
||||
|
||||
function _update_min_padding!(sp::Subplot{GastonBackend})
|
||||
sp.minpad = (20mm, 5mm, 2mm, 10mm)
|
||||
end
|
||||
|
||||
function _update_plot_object(plt::Plot{GastonBackend})
|
||||
end
|
||||
|
||||
for (mime, term) in (
|
||||
"application/eps" => "epscairo", # NEED fixing TODO
|
||||
"image/eps" => "epslatex", # NEED fixing TODO
|
||||
"application/pdf" => "pdfcairo", # NEED fixing TODO
|
||||
"application/postscript" => "postscript", # NEED fixing TODO
|
||||
"image/svg+xml" => "svg",
|
||||
"text/latex" => "tikz", # NEED fixing TODO
|
||||
"application/x-tex" => "epslatex", # NEED fixing TODO
|
||||
"text/plain" => "dumb", # NEED fixing TODO
|
||||
)
|
||||
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GastonBackend})
|
||||
xsize = plt.attr[:size][1]
|
||||
ysize = plt.attr[:size][2]
|
||||
termopts="""size $xsize,$ysize"""
|
||||
|
||||
tmpfile = G.tempname() * "." * $term
|
||||
|
||||
G.save(
|
||||
term = $term,
|
||||
output = tmpfile,
|
||||
handle = plt.o.handle,
|
||||
saveopts = termopts
|
||||
)
|
||||
while !isfile(tmpfile) end # avoid race condition with read in next line
|
||||
write(io, read(tmpfile))
|
||||
rm(tmpfile, force=true)
|
||||
nothing
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME{Symbol("image/png")},
|
||||
plt::Plot{GastonBackend},)
|
||||
scaling = plt.attr[:dpi] / GNUPLOT_DPI
|
||||
xsize = plt.attr[:size][1] * scaling
|
||||
ysize = plt.attr[:size][2] * scaling
|
||||
|
||||
# Scale all plot elements to match Plots.jl DPI standard
|
||||
termopts="""size $xsize,$ysize fontscale $scaling lw $scaling dl $scaling ps $scaling"""
|
||||
|
||||
tmpfile = G.tempname()
|
||||
|
||||
G.save(
|
||||
term = "pngcairo",
|
||||
output = tmpfile,
|
||||
handle = plt.o.handle,
|
||||
saveopts = termopts
|
||||
)
|
||||
while !isfile(tmpfile) end # avoid race condition with read in next line
|
||||
write(io, read(tmpfile))
|
||||
rm(tmpfile, force=true)
|
||||
nothing
|
||||
end
|
||||
|
||||
|
||||
function _display(plt::Plot{GastonBackend})
|
||||
display(plt.o)
|
||||
end
|
||||
#
|
||||
# --------------------------------------------
|
||||
# These functions are gaston specific
|
||||
# --------------------------------------------
|
||||
#
|
||||
function gaston_init_subplot(plt::Plot{GastonBackend}, sp::Subplot{GastonBackend})
|
||||
dims = RecipesPipeline.is3d(sp) ? 3 : 2
|
||||
|
||||
axesconf = gaston_parse_axes_args(plt, sp) # Gnuplot string
|
||||
sp.o = GastonSubplot(dims=dims, axesconf = axesconf, curves = [])
|
||||
push!(plt.o.subplots, sp.o)
|
||||
|
||||
end
|
||||
|
||||
function gaston_add_series(plt::Plot{GastonBackend}, series::Series)
|
||||
# Gaston.Curve = Plots.Series
|
||||
sp = series[:subplot]
|
||||
g_sp = sp.o # Gaston subplot object
|
||||
|
||||
seriesconf = gaston_parse_series_args(series) # Gnuplot string
|
||||
c = G.Curve(series[:x], series[:y], nothing, nothing, seriesconf )
|
||||
|
||||
isfirst = length(g_sp.curves) == 0 ? true : false
|
||||
push!(g_sp.curves, c)
|
||||
G.write_data(c, g_sp.dims, g_sp.datafile, append = isfirst ? false : true)
|
||||
end
|
||||
|
||||
function gaston_parse_series_args(series::Series)
|
||||
curveconf = String[]
|
||||
st = series[:seriestype]
|
||||
|
||||
if st == :scatter
|
||||
pt = gaston_marker(series[:markershape])
|
||||
ps = series[:markersize] * GASTON_MARKER_SCALING
|
||||
lc = gaston_color(series[:markercolor])
|
||||
# alpha = series[:markeralpha] # TODO merge alpha with rgb color
|
||||
push!(curveconf, """with points pt $pt ps $ps lc $lc""")
|
||||
elseif st == :path
|
||||
lc = gaston_color(series[:linecolor])
|
||||
dt = gaston_linestyle(series[:linestyle])
|
||||
lw = series[:linewidth]
|
||||
# alpha = series[:linealpha] # TODO merge alpha with rgb color
|
||||
if series[:markershape] == :none # simplepath
|
||||
push!(curveconf, """with lines lc $lc dt $dt lw $lw""")
|
||||
else
|
||||
pt = gaston_marker(series[:markershape])
|
||||
ps = series[:markersize] * GASTON_MARKER_SCALING
|
||||
push!(curveconf, """with lp lc $lc dt $dt lw $lw pt $pt ps $ps""")
|
||||
end
|
||||
elseif st == :shape
|
||||
fc = gaston_color(series[:fillcolor])
|
||||
fs = "solid"
|
||||
lc = gaston_color(series[:linecolor])
|
||||
push!(curveconf, """with filledcurves fc $fc fs $fs border lc $lc""")
|
||||
elseif st == :steppre
|
||||
push!(curveconf, """with steps""")
|
||||
elseif st == :steppost
|
||||
push!(curveconf, """with fsteps""") # Not sure if not the other way
|
||||
end
|
||||
|
||||
# label
|
||||
push!(curveconf, """title "$(series[:label])" """)
|
||||
|
||||
return join(curveconf, " ")
|
||||
end
|
||||
|
||||
function gaston_parse_axes_args(plt::Plot{GastonBackend}, sp::Subplot{GastonBackend})
|
||||
axesconf = String[]
|
||||
# Standard 2d axis
|
||||
if !ispolar(sp) && !RecipesPipeline.is3d(sp)
|
||||
# TODO
|
||||
# configure grid, axis spines, thickness
|
||||
end
|
||||
|
||||
for letter in (:x, :y, :z)
|
||||
axis_attr = sp.attr[Symbol(letter, :axis)]
|
||||
# label names
|
||||
push!(axesconf, """set $(letter)label "$(axis_attr[:guide])" """)
|
||||
push!(axesconf, """set $(letter)label font "$(axis_attr[:guidefontfamily]), $(axis_attr[:guidefontsize])" """)
|
||||
|
||||
# Handle ticks
|
||||
# ticksyle
|
||||
push!(axesconf, """set $(letter)tics font "$(axis_attr[:tickfontfamily]), $(axis_attr[:tickfontsize])" """)
|
||||
push!(axesconf, """set $(letter)tics textcolor rgb "#$(hex(axis_attr[:tickfontcolor], :rrggbb))" """)
|
||||
push!(axesconf, """set $(letter)tics $(axis_attr[:tick_direction])""")
|
||||
|
||||
mirror = axis_attr[:mirror] ? "mirror" : "nomirror"
|
||||
push!(axesconf, """set $(letter)tics $(mirror) """)
|
||||
|
||||
logscale = if axis_attr[:scale] == :identity
|
||||
"nologscale"
|
||||
elseif axis_attr[:scale] == :log10
|
||||
"logscale"
|
||||
end
|
||||
push!(axesconf, """set $logscale $(letter)""")
|
||||
|
||||
# tick locations
|
||||
if axis_attr[:ticks] != :native
|
||||
# axis limits
|
||||
from, to = axis_limits(sp, letter)
|
||||
push!(axesconf, """set $(letter)range [$from:$to]""")
|
||||
|
||||
ticks = get_ticks(sp, axis_attr)
|
||||
gaston_set_ticks!(axesconf, ticks, letter)
|
||||
end
|
||||
# set title {"<title-text>"} {offset <offset>} {font "<font>{,<size>}"}{{textcolor | tc} {<colorspec> | default}} {{no}enhanced}1
|
||||
end
|
||||
gaston_set_legend!(axesconf, sp) # Set legend params
|
||||
|
||||
if sp[:title] != nothing
|
||||
push!(axesconf, """set title '$(sp[:title])' """)
|
||||
push!(axesconf, """set title font '$(sp[:titlefontfamily]), $(sp[:titlefontsize])' """)
|
||||
end
|
||||
|
||||
return join(axesconf, "\n")
|
||||
end
|
||||
|
||||
function gaston_set_ticks!(axesconf, ticks, letter)
|
||||
|
||||
ticks == :auto && return
|
||||
if ticks == :none || ticks === nothing || ticks == false
|
||||
push!(axesconf, """unset $(letter)tics """)
|
||||
return
|
||||
end
|
||||
|
||||
ttype = ticksType(ticks)
|
||||
if ttype == :ticks
|
||||
tick_locations = @view ticks[:]
|
||||
gaston_tick_string = []
|
||||
for i in eachindex(tick_locations)
|
||||
lac = tick_locations[i]
|
||||
push!(gaston_tick_string, "$loc")
|
||||
end
|
||||
push!(
|
||||
axesconf,
|
||||
"set $(letter)tics (" * join(gaston_tick_string, ", ") * ")"
|
||||
)
|
||||
|
||||
elseif ttype == :ticks_and_labels
|
||||
tick_locations = @view ticks[1][:]
|
||||
tick_labels = @view ticks[2][:]
|
||||
gaston_tick_string = []
|
||||
for i in eachindex(tick_locations)
|
||||
loc = tick_locations[i]
|
||||
lab = gaston_enclose_tick_string(tick_labels[i])
|
||||
push!(gaston_tick_string, "'$lab' $loc")
|
||||
end
|
||||
push!(
|
||||
axesconf,
|
||||
"set $(letter)tics (" * join(gaston_tick_string, ", ") * ")"
|
||||
)
|
||||
|
||||
else
|
||||
error("Invalid input for $(letter)ticks: $ticks")
|
||||
end
|
||||
end
|
||||
|
||||
function gaston_set_legend!(axesconf, sp)
|
||||
leg = sp[:legend]
|
||||
if !(sp[:legend] in(:none, :inline))
|
||||
if leg == :best
|
||||
leg = :topright
|
||||
end
|
||||
|
||||
if occursin("outer", string(leg))
|
||||
push!(axesconf, "set key outside")
|
||||
else
|
||||
push!(axesconf, "set key inside")
|
||||
end
|
||||
positions = ["top", "bottom", "left", "right"]
|
||||
for position in positions
|
||||
if occursin(position, string(leg))
|
||||
push!(axesconf, "set key $position")
|
||||
end
|
||||
end
|
||||
if sp[:legendtitle] != nothing
|
||||
push!(axesconf, "set key title '$(sp[:legendtitle])'")
|
||||
end
|
||||
push!(axesconf, "set key box linewidth 1")
|
||||
push!(axesconf, "set key opaque")
|
||||
|
||||
push!(axesconf, "set border back")
|
||||
push!(axesconf, """set key font "$(sp[:legendfontfamily]), $(sp[:legendfontsize])" """)
|
||||
else
|
||||
push!(axesconf, "set key off")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function gaston_marker(marker)
|
||||
marker == :none && return -1
|
||||
marker == :circle && return 7
|
||||
marker == :rect && return 5
|
||||
marker == :diamond && return 28
|
||||
marker == :utriangle && return 9
|
||||
marker == :dtriangle && return 11
|
||||
marker == :+ && return 1
|
||||
marker == :x && return 2
|
||||
marker == :star5 && return 3
|
||||
marker == :pentagon && return 15
|
||||
marker == :pixel && return 0
|
||||
|
||||
@warn("Unsupported marker $marker")
|
||||
return 1
|
||||
end
|
||||
|
||||
gaston_color(color) = """rgb "#$(hex(color, :rrggbb))" """
|
||||
|
||||
function gaston_linestyle(style)
|
||||
style == :solid && return "1"
|
||||
style == :dash && return "2"
|
||||
style == :dot && return "3"
|
||||
style == :dashdot && return "4"
|
||||
style == :dashdotdot && return "5"
|
||||
end
|
||||
|
||||
function gaston_enclose_tick_string(tick_string)
|
||||
if findfirst("^", tick_string) == nothing
|
||||
return tick_string
|
||||
end
|
||||
|
||||
|
||||
base, power = split(tick_string, "^")
|
||||
power = string("{", power, "}")
|
||||
return string(base, "^", power)
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
+1569
-989
File diff suppressed because it is too large
Load Diff
+518
-536
File diff suppressed because it is too large
Load Diff
+137
-144
@@ -13,70 +13,10 @@ Add in functionality to Plots.jl:
|
||||
:aspect_ratio,
|
||||
=#
|
||||
|
||||
@require Revise begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "inspectdr.jl"))
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
#TODO: remove features
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_grid,
|
||||
:foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokestyle, #Causes warning not to have it... what is this?
|
||||
:fillcolor, :fillalpha, #:fillrange,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location,
|
||||
:window_title,
|
||||
:guide, :lims, :scale, #:ticks, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :legend, #:colorbar,
|
||||
# :marker_z,
|
||||
# :line_z,
|
||||
# :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
:dpi,
|
||||
# :colorbar_title,
|
||||
])
|
||||
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _inspectdr_seriestype = [
|
||||
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
|
||||
]
|
||||
#see: _allMarkers, _shape_keys
|
||||
const _inspectdr_marker = Symbol[
|
||||
:none, :auto,
|
||||
:circle, :rect, :diamond,
|
||||
:cross, :xcross,
|
||||
:utriangle, :dtriangle, :rtriangle, :ltriangle,
|
||||
:pentagon, :hexagon, :heptagon, :octagon,
|
||||
:star4, :star5, :star6, :star7, :star8,
|
||||
:vline, :hline, :+, :x,
|
||||
]
|
||||
|
||||
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
is_marker_supported(::InspectDRBackend, shape::Shape) = true
|
||||
|
||||
_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
|
||||
@@ -90,24 +30,24 @@ end
|
||||
|
||||
# py_marker(markers::AVec) = map(py_marker, markers)
|
||||
function _inspectdr_mapglyph(markers::AVec)
|
||||
warn("Vectors of markers are currently unsupported in InspectDR.")
|
||||
@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.")
|
||||
@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.")
|
||||
@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.")
|
||||
@warn("Vectors of colors are currently unsupported in InspectDR.")
|
||||
#Pick middle color:
|
||||
_inspectdr_mapcolor(v[div(1+end,2)])
|
||||
end
|
||||
@@ -136,6 +76,58 @@ 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
|
||||
@@ -152,37 +144,23 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::InspectDRBackend)
|
||||
"""
|
||||
if !Plots.is_installed("InspectDR")
|
||||
Pkg.add("InspectDR")
|
||||
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
|
||||
|
||||
function _initialize_backend(::InspectDRBackend; kw...)
|
||||
@eval begin
|
||||
import InspectDR
|
||||
export InspectDR
|
||||
_inspectdr_getmplot(::Any) = nothing
|
||||
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
|
||||
|
||||
#Glyph used when plotting "Shape"s:
|
||||
const INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
|
||||
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
|
||||
)
|
||||
|
||||
mutable struct InspecDRPlotRef
|
||||
mplot::Union{Void, InspectDR.Multiplot}
|
||||
gui::Union{Void, 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)
|
||||
end
|
||||
end
|
||||
_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)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -192,9 +170,9 @@ function _create_backend_figure(plt::Plot{InspectDRBackend})
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
#:overwrite_figure: want to reuse current figure
|
||||
if plt[:overwrite_figure] && mplot != nothing
|
||||
if plt[:overwrite_figure] && mplot !== nothing
|
||||
mplot.subplots = [] #Reset
|
||||
if gplot != nothing #Ensure still references current plot
|
||||
if gplot !== nothing #Ensure still references current plot
|
||||
gplot.src = mplot
|
||||
end
|
||||
else #want new one:
|
||||
@@ -238,6 +216,7 @@ 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
|
||||
@@ -278,8 +257,10 @@ For st in :shape:
|
||||
nmax = i
|
||||
if length(rng) > 1
|
||||
linewidth = series[:linewidth]
|
||||
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
|
||||
c = plot_color(get_linecolor(series), get_linealpha(series))
|
||||
linecolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
c = plot_color(get_fillcolor(series), get_fillalpha(series))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
line = InspectDR.line(
|
||||
style=:solid, width=linewidth, color=linecolor
|
||||
)
|
||||
@@ -293,8 +274,10 @@ For st in :shape:
|
||||
i = (nmax >= 2 ? div(nmax, 2) : nmax) #Must pick one set of colors for legend
|
||||
if i > 1 #Add dummy waveform for legend entry:
|
||||
linewidth = series[:linewidth]
|
||||
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
|
||||
c = plot_color(get_linecolor(series), get_linealpha(series))
|
||||
linecolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
c = plot_color(get_fillcolor(series), get_fillalpha(series))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
|
||||
wfrm = InspectDR.add(plot, Float64[], Float64[], id=series[:label])
|
||||
wfrm.line = InspectDR.line(
|
||||
style=:none, width=linewidth, #linewidth affects glyph
|
||||
@@ -304,7 +287,7 @@ For st in :shape:
|
||||
color = linecolor, fillcolor = fillcolor
|
||||
)
|
||||
end
|
||||
elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost)
|
||||
elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost)
|
||||
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
|
||||
linewidth = series[:linewidth]
|
||||
#More efficient & allows some support for markerstrokewidth:
|
||||
@@ -313,7 +296,7 @@ For st in :shape:
|
||||
wfrm.line = InspectDR.line(
|
||||
style = _style,
|
||||
width = series[:linewidth],
|
||||
color = series[:linecolor],
|
||||
color = plot_color(get_linecolor(series), get_linealpha(series)),
|
||||
)
|
||||
#InspectDR does not control markerstrokewidth independently.
|
||||
if :none == _style
|
||||
@@ -323,8 +306,8 @@ For st in :shape:
|
||||
wfrm.glyph = InspectDR.glyph(
|
||||
shape = _inspectdr_mapglyph(series[:markershape]),
|
||||
size = _inspectdr_mapglyphsize(series[:markersize]),
|
||||
color = _inspectdr_mapcolor(series[:markerstrokecolor]),
|
||||
fillcolor = _inspectdr_mapcolor(series[:markercolor]),
|
||||
color = _inspectdr_mapcolor(plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series))),
|
||||
fillcolor = _inspectdr_mapcolor(plot_color(get_markercolor(series, clims), get_markeralpha(series))),
|
||||
)
|
||||
end
|
||||
|
||||
@@ -347,66 +330,76 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
const plot = sp.o
|
||||
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
|
||||
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,
|
||||
vmajor=xgrid_show, # vminor=xgrid_show,
|
||||
hmajor=ygrid_show, # hminor=ygrid_show,
|
||||
)
|
||||
|
||||
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
|
||||
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
|
||||
xmin, xmax = axis_limits(xaxis)
|
||||
ymin, ymax = axis_limits(yaxis)
|
||||
xmin, xmax = axis_limits(sp, :x)
|
||||
ymin, ymax = axis_limits(sp, :y)
|
||||
if ispolar(sp)
|
||||
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
|
||||
rmax = NaNMath.max(abs(ymin), abs(ymax))
|
||||
xmin, xmax = -rmax, rmax
|
||||
ymin, ymax = -rmax, rmax
|
||||
end
|
||||
plot.xext = InspectDR.PExtents1D() #reset
|
||||
strip.yext = InspectDR.PExtents1D() #reset
|
||||
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
|
||||
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l[:font_title] = InspectDR.Font(sp[:titlefontfamily],
|
||||
#Modify base layout of new object:
|
||||
l = plot.layout.defaults = deepcopy(InspectDR.defaults.plotlayout)
|
||||
#IMPORTANT: Must deepcopy to ensure we don't change layouts of other plots.
|
||||
#Works because plot uses defaults (not user-overwritten `layout.values`)
|
||||
l.frame_canvas.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l.frame_data.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l.frame_data.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l.font_title = InspectDR.Font(sp[: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],
|
||||
l.font_axislabel = InspectDR.Font(xaxis[:guidefontfamily],
|
||||
_inspectdr_mapptsize(xaxis[:guidefontsize]),
|
||||
color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
|
||||
)
|
||||
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfontfamily],
|
||||
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],
|
||||
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.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
|
||||
#_round!() ensures values use integer spacings (looks better on screen):
|
||||
InspectDR._round!(InspectDR.autofit2font!(l, legend_width=10.0)) #10 "em"s wide
|
||||
return
|
||||
end
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
# for the calcs
|
||||
function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
const mplot = _inspectdr_getmplot(plt.o)
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
|
||||
mplot.title = plt[:plot_title]
|
||||
@@ -414,8 +407,9 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
#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].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)
|
||||
@@ -475,15 +469,20 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
# 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
|
||||
mplot.bblist = InspectDR.BoundingBox[]
|
||||
|
||||
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)
|
||||
figw, figh = sp.plt[:size]
|
||||
pcts = bbox_to_pcts(sp.bbox, figw*px, figh*px)
|
||||
_left, _bottom, _width, _height = pcts
|
||||
ymax = 1.0-_bottom
|
||||
ymin = ymax - _height
|
||||
bb = InspectDR.BoundingBox(_left, _left+_width, ymin, ymax)
|
||||
push!(mplot.bblist, bb)
|
||||
end
|
||||
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
@@ -496,29 +495,23 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _inspectdr_mimeformats_dpi = Dict(
|
||||
"image/png" => "png"
|
||||
)
|
||||
const _inspectdr_mimeformats_nodpi = Dict(
|
||||
"image/svg+xml" => "svg",
|
||||
"application/eps" => "eps",
|
||||
"image/eps" => "eps",
|
||||
# "application/postscript" => "ps", #TODO: support once Cairo supports PSSurface
|
||||
"application/pdf" => "pdf"
|
||||
)
|
||||
_inspectdr_show(io::IO, mime::MIME, ::Void, w, h) =
|
||||
_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
|
||||
|
||||
for (mime, fmt) in _inspectdr_mimeformats_dpi
|
||||
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{InspectDRBackend})
|
||||
dpi = plt[:dpi]#TODO: support
|
||||
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
|
||||
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 _inspectdr_mimeformats_nodpi
|
||||
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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+442
-384
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
+32
-115
@@ -1,130 +1,45 @@
|
||||
@require Revise begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
|
||||
end
|
||||
# https://github.com/sglyon/PlotlyJS.jl
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const _plotlyjs_attr = _plotly_attr
|
||||
const _plotlyjs_seriestype = _plotly_seriestype
|
||||
const _plotlyjs_style = _plotly_style
|
||||
const _plotlyjs_marker = _plotly_marker
|
||||
const _plotlyjs_scale = _plotly_scale
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function add_backend_string(::PlotlyJSBackend)
|
||||
"""
|
||||
if !Plots.is_installed("PlotlyJS")
|
||||
Pkg.add("PlotlyJS")
|
||||
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
|
||||
if !Plots.is_installed("Rsvg")
|
||||
Pkg.add("Rsvg")
|
||||
end
|
||||
import Blink
|
||||
Blink.AtomShell.install()
|
||||
"""
|
||||
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
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::PlotlyJSBackend; kw...)
|
||||
@eval begin
|
||||
import PlotlyJS
|
||||
export PlotlyJS
|
||||
end
|
||||
|
||||
# # override IJulia inline display
|
||||
# if isijulia()
|
||||
# IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(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)
|
||||
|
||||
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
|
||||
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
|
||||
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
|
||||
else
|
||||
PlotlyJS.plot()
|
||||
end
|
||||
end
|
||||
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = write(io, embeddable_html(plt))
|
||||
|
||||
_display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt))
|
||||
|
||||
function _series_added(plt::Plot{PlotlyJSBackend}, series::Series)
|
||||
syncplot = plt.o
|
||||
pdicts = plotly_series(plt, series)
|
||||
for pdict in pdicts
|
||||
typ = pop!(pdict, :type)
|
||||
gt = PlotlyJS.GenericTrace(typ; pdict...)
|
||||
PlotlyJS.addtraces!(syncplot, gt)
|
||||
end
|
||||
end
|
||||
|
||||
function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
|
||||
xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y))
|
||||
kw = KW(xsym => (series.d[:x],), ysym => (series.d[:y],))
|
||||
z = series[:z]
|
||||
if z != nothing
|
||||
kw[:z] = (isa(z,Surface) ? transpose_z(series, series[:z].surf, false) : z,)
|
||||
end
|
||||
PlotlyJS.restyle!(
|
||||
plt.o,
|
||||
findfirst(plt.series_list, series),
|
||||
kw
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _update_plot_object(plt::Plot{PlotlyJSBackend})
|
||||
pdict = plotly_layout(plt)
|
||||
syncplot = plt.o
|
||||
w,h = plt[:size]
|
||||
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
|
||||
if isijulia() && !_use_remote[]
|
||||
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
|
||||
else
|
||||
show(io, MIME("text/html"), plt.o)
|
||||
end
|
||||
end
|
||||
|
||||
function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
|
||||
tmpfn = tempname() * "." * ext
|
||||
PlotlyJS.savefig(plt.o, tmpfn)
|
||||
write(io, read(open(tmpfn)))
|
||||
end
|
||||
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
|
||||
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
|
||||
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
|
||||
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
|
||||
|
||||
function write_temp_html(plt::Plot{PlotlyJSBackend})
|
||||
filename = string(tempname(), ".html")
|
||||
savefig(plt, filename)
|
||||
filename
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PlotlyJSBackend})
|
||||
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
|
||||
display(plt.o)
|
||||
else
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
end
|
||||
|
||||
@require WebIO begin
|
||||
function WebIO.render(plt::Plot{PlotlyJSBackend})
|
||||
prepare_output(plt)
|
||||
WebIO.render(plt.o)
|
||||
end
|
||||
function PlotlyJS.WebIO.render(plt::Plot{PlotlyJSBackend})
|
||||
return PlotlyJS.WebIO.render(plotlyjs_syncplot(plt))
|
||||
end
|
||||
|
||||
function closeall(::PlotlyJSBackend)
|
||||
@@ -132,3 +47,5 @@ function closeall(::PlotlyJSBackend)
|
||||
close(current().o)
|
||||
end
|
||||
end
|
||||
|
||||
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot{PlotlyJSBackend}) = true
|
||||
|
||||
+629
-509
File diff suppressed because it is too large
Load Diff
@@ -1,63 +1,19 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
@require Revise begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
|
||||
end
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor,
|
||||
:seriesalpha,
|
||||
:linestyle,
|
||||
:markershape,
|
||||
:bins,
|
||||
:title,
|
||||
:guide, :lims,
|
||||
])
|
||||
const _unicodeplots_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
# :bar,
|
||||
:shape,
|
||||
:histogram2d,
|
||||
:spy
|
||||
]
|
||||
const _unicodeplots_style = [:auto, :solid]
|
||||
const _unicodeplots_marker = [:none, :auto, :circle]
|
||||
const _unicodeplots_scale = [:identity]
|
||||
|
||||
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warnOnUnsupported_args(::UnicodePlotsBackend, d::KW) = nothing
|
||||
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::UnicodePlotsBackend)
|
||||
"""
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.build("UnicodePlots")
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::UnicodePlotsBackend; kw...)
|
||||
@eval begin
|
||||
import UnicodePlots
|
||||
export UnicodePlots
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
const _canvas_type = Ref(:auto)
|
||||
|
||||
function _canvas_map()
|
||||
KW(
|
||||
:braille => UnicodePlots.BrailleCanvas,
|
||||
:ascii => UnicodePlots.AsciiCanvas,
|
||||
:block => UnicodePlots.BlockCanvas,
|
||||
:dot => UnicodePlots.DotCanvas,
|
||||
:density => UnicodePlots.DensityCanvas,
|
||||
(
|
||||
braille = UnicodePlots.BrailleCanvas,
|
||||
ascii = UnicodePlots.AsciiCanvas,
|
||||
block = UnicodePlots.BlockCanvas,
|
||||
dot = UnicodePlots.DotCanvas,
|
||||
density = UnicodePlots.DensityCanvas,
|
||||
)
|
||||
end
|
||||
|
||||
@@ -69,8 +25,8 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
for sp in plt.subplots
|
||||
xaxis = sp[:xaxis]
|
||||
yaxis = sp[:yaxis]
|
||||
xlim = axis_limits(xaxis)
|
||||
ylim = axis_limits(yaxis)
|
||||
xlim = axis_limits(sp, :x)
|
||||
ylim = axis_limits(sp, :y)
|
||||
|
||||
# make vectors
|
||||
xlim = [xlim[1], xlim[2]]
|
||||
@@ -124,7 +80,7 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
for series in series_list(sp)
|
||||
addUnicodeSeries!(o, series.d, sp[:legend] != :none, xlim, ylim)
|
||||
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
|
||||
end
|
||||
|
||||
# save the object
|
||||
@@ -134,17 +90,17 @@ end
|
||||
|
||||
|
||||
# add a single series
|
||||
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
|
||||
function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim)
|
||||
# get the function, or special handling for step/bar/hist
|
||||
st = d[:seriestype]
|
||||
st = plotattributes[:seriestype]
|
||||
if st == :histogram2d
|
||||
UnicodePlots.densityplot!(o, d[:x], d[:y])
|
||||
UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
|
||||
return
|
||||
end
|
||||
|
||||
if st in (:path, :straightline)
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif st == :scatter || d[:markershape] != :none
|
||||
elseif st == :scatter || plotattributes[:markershape] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
# elseif st == :bar
|
||||
# func = UnicodePlots.barplot!
|
||||
@@ -156,19 +112,19 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
|
||||
|
||||
# get the series data and label
|
||||
x, y = if st == :straightline
|
||||
straightline_data(d)
|
||||
straightline_data(plotattributes)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
shape_data(plotattributes)
|
||||
else
|
||||
[collect(float(d[s])) for s in (:x, :y)]
|
||||
[collect(float(plotattributes[s])) for s in (:x, :y)]
|
||||
end
|
||||
label = addlegend ? d[:label] : ""
|
||||
label = addlegend ? plotattributes[:label] : ""
|
||||
|
||||
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
|
||||
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
|
||||
color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto
|
||||
|
||||
# add the series
|
||||
x, y = Plots.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
|
||||
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
|
||||
|
||||
@@ -183,7 +139,7 @@ function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
|
||||
gui(plt)
|
||||
|
||||
# @osx_only begin
|
||||
@static if is_apple()
|
||||
@static if Sys.isapple()
|
||||
# BEGIN HACK
|
||||
|
||||
# wait while the plot gets drawn
|
||||
|
||||
+14
-7
@@ -2,9 +2,6 @@
|
||||
# NOTE: backend should implement `html_body` and `html_head`
|
||||
|
||||
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
|
||||
@require Revise begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
|
||||
end
|
||||
|
||||
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
|
||||
"""
|
||||
@@ -22,17 +19,21 @@ function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr
|
||||
"""
|
||||
end
|
||||
|
||||
function embeddable_html(plt::AbstractPlot)
|
||||
html_head(plt) * html_body(plt)
|
||||
end
|
||||
|
||||
function open_browser_window(filename::AbstractString)
|
||||
@static if is_apple()
|
||||
@static if Sys.isapple()
|
||||
return run(`open $(filename)`)
|
||||
end
|
||||
@static if is_linux() || is_bsd() # is_bsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
|
||||
@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 is_windows()
|
||||
@static if Sys.iswindows()
|
||||
return run(`$(ENV["COMSPEC"]) /c start "" "$(filename)"`)
|
||||
end
|
||||
warn("Unknown OS... cannot open browser window.")
|
||||
@warn("Unknown OS... cannot open browser window.")
|
||||
end
|
||||
|
||||
function write_temp_html(plt::AbstractPlot)
|
||||
@@ -45,8 +46,14 @@ function write_temp_html(plt::AbstractPlot)
|
||||
end
|
||||
|
||||
function standalone_html_window(plt::AbstractPlot)
|
||||
old = use_local_dependencies[] # save state to restore afterwards
|
||||
# if we open a browser ourself, we can host local files, so
|
||||
# when we have a local plotly downloaded this is the way to go!
|
||||
use_local_dependencies[] = 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
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# These functions return an operator for use in `get_clims(::Seres, op)`
|
||||
process_clims(lims::Tuple{<:Number,<:Number}) = (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ∘ ignorenan_extrema
|
||||
process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema
|
||||
# don't specialize on ::Function otherwise python functions won't work
|
||||
process_clims(f) = f
|
||||
|
||||
function get_clims(sp::Subplot, op=process_clims(sp[:clims]))
|
||||
zmin, zmax = Inf, -Inf
|
||||
for series in series_list(sp)
|
||||
if series[:colorbar_entry]
|
||||
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
|
||||
end
|
||||
end
|
||||
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
end
|
||||
|
||||
function get_clims(sp::Subplot, series::Series, op=process_clims(sp[:clims]))
|
||||
zmin, zmax = if series[:colorbar_entry]
|
||||
get_clims(sp, op)
|
||||
else
|
||||
get_clims(series, op)
|
||||
end
|
||||
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
end
|
||||
|
||||
"""
|
||||
get_clims(::Series, op=Plots.ignorenan_extrema)
|
||||
|
||||
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
|
||||
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
|
||||
values of the input.
|
||||
"""
|
||||
function get_clims(series::Series, op=ignorenan_extrema)
|
||||
zmin, zmax = Inf, -Inf
|
||||
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
|
||||
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
|
||||
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real})
|
||||
zmin, zmax = _update_clims(zmin, zmax, op(vals.surf)...)
|
||||
elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real})
|
||||
zmin, zmax = _update_clims(zmin, zmax, op(vals)...)
|
||||
end
|
||||
end
|
||||
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
end
|
||||
|
||||
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
|
||||
|
||||
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
|
||||
|
||||
function colorbar_style(series::Series)
|
||||
colorbar_entry = series[:colorbar_entry]
|
||||
if !(colorbar_entry isa Bool)
|
||||
@warn "Non-boolean colorbar_entry ignored."
|
||||
colorbar_entry = true
|
||||
end
|
||||
|
||||
if !colorbar_entry
|
||||
nothing
|
||||
elseif isfilledcontour(series)
|
||||
cbar_fill
|
||||
elseif iscontour(series)
|
||||
cbar_lines
|
||||
elseif series[:seriestype] ∈ (:heatmap,:surface) ||
|
||||
any(series[z] !== nothing for z ∈ [:marker_z,:line_z,:fill_z])
|
||||
cbar_gradient
|
||||
else
|
||||
nothing
|
||||
end
|
||||
end
|
||||
|
||||
hascolorbar(series::Series) = colorbar_style(series) !== nothing
|
||||
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
|
||||
|
||||
function get_colorbar_ticks(sp::Subplot; update = true)
|
||||
if update || !haskey(sp.attr, :colorbar_optimized_ticks)
|
||||
ticks = _transform_ticks(sp[:colorbar_ticks])
|
||||
cvals = sp[:colorbar_continuous_values]
|
||||
dvals = sp[:colorbar_discrete_values]
|
||||
clims = get_clims(sp)
|
||||
scale = sp[:colorbar_scale]
|
||||
formatter = sp[:colorbar_formatter]
|
||||
sp.attr[:colorbar_optimized_ticks] =
|
||||
get_ticks(ticks, cvals, dvals, clims, scale, formatter)
|
||||
end
|
||||
return sp.attr[:colorbar_optimized_ticks]
|
||||
end
|
||||
|
||||
function _update_subplot_colorbars(sp::Subplot)
|
||||
# Dynamic callback from the pipeline if needed
|
||||
end
|
||||
+165
-143
@@ -1,19 +1,17 @@
|
||||
|
||||
|
||||
const P2 = FixedSizeArrays.Vec{2,Float64}
|
||||
const P3 = FixedSizeArrays.Vec{3,Float64}
|
||||
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 = atan2(v[2], v[1]); angle < 0 ? 2π - angle : angle)
|
||||
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
|
||||
struct Shape
|
||||
x::Vector{Float64}
|
||||
y::Vector{Float64}
|
||||
struct Shape{X<:Number, Y<:Number}
|
||||
x::Vector{X}
|
||||
y::Vector{Y}
|
||||
# function Shape(x::AVec, y::AVec)
|
||||
# # if x[1] != x[end] || y[1] != y[end]
|
||||
# # new(vcat(x, x[1]), vcat(y, y[1]))
|
||||
@@ -29,7 +27,7 @@ end
|
||||
|
||||
Construct a polygon to be plotted
|
||||
"""
|
||||
Shape(verts::AVec) = Shape(unzip(verts)...)
|
||||
Shape(verts::AVec) = Shape(RecipesPipeline.unzip(verts)...)
|
||||
Shape(s::Shape) = deepcopy(s)
|
||||
|
||||
get_xs(shape::Shape) = shape.x
|
||||
@@ -44,21 +42,17 @@ 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
|
||||
#coords(shapes::AVec{Shape}) = unzip(map(coords, shapes))
|
||||
function coords(shapes::AVec{<:Shape})
|
||||
c = map(coords, shapes)
|
||||
x = [q[1] for q in c]
|
||||
y = [q[2] for q in c]
|
||||
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 linspace(start_θ, end_θ, n)]
|
||||
[(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)"
|
||||
@@ -68,7 +62,8 @@ function weave(x,y; ordering = Vector[x,y])
|
||||
while !done
|
||||
for o in ordering
|
||||
try
|
||||
push!(ret, shift!(o))
|
||||
push!(ret, popfirst!(o))
|
||||
catch
|
||||
end
|
||||
end
|
||||
done = isempty(x) && isempty(y)
|
||||
@@ -76,7 +71,6 @@ function weave(x,y; ordering = Vector[x,y])
|
||||
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 * π
|
||||
@@ -92,7 +86,6 @@ function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius))
|
||||
end
|
||||
|
||||
|
||||
function makecross(; offset = -0.5, radius = 1.0)
|
||||
z2 = offset * π
|
||||
z1 = z2 - π/8
|
||||
@@ -102,7 +95,6 @@ function makecross(; offset = -0.5, radius = 1.0)
|
||||
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)
|
||||
@@ -111,31 +103,6 @@ function makearrowhead(angle; h = 2.0, w = 0.4)
|
||||
from_polar(angle + 0.5π, w) - tip, (0,0)])
|
||||
end
|
||||
|
||||
const _shape_keys = Symbol[
|
||||
:circle,
|
||||
:rect,
|
||||
:star5,
|
||||
:diamond,
|
||||
:hexagon,
|
||||
:cross,
|
||||
:xcross,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:rtriangle,
|
||||
:ltriangle,
|
||||
:pentagon,
|
||||
:heptagon,
|
||||
:octagon,
|
||||
:star4,
|
||||
:star6,
|
||||
:star7,
|
||||
:star8,
|
||||
:vline,
|
||||
:hline,
|
||||
:+,
|
||||
:x,
|
||||
]
|
||||
|
||||
const _shapes = KW(
|
||||
:circle => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
@@ -186,7 +153,7 @@ end
|
||||
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
sx, sy = coords(shape)
|
||||
cx, cy = c
|
||||
for i=1:length(sx)
|
||||
for i=eachindex(sx)
|
||||
sx[i] = (sx[i] - cx) * x + cx
|
||||
sy[i] = (sy[i] - cy) * y + cy
|
||||
end
|
||||
@@ -201,7 +168,7 @@ end
|
||||
"translate a Shape in space"
|
||||
function translate!(shape::Shape, x::Real, y::Real = x)
|
||||
sx, sy = coords(shape)
|
||||
for i=1:length(sx)
|
||||
for i=eachindex(sx)
|
||||
sx[i] += x
|
||||
sy[i] += y
|
||||
end
|
||||
@@ -229,7 +196,7 @@ end
|
||||
function rotate!(shape::Shape, Θ::Real, c = center(shape))
|
||||
x, y = coords(shape)
|
||||
cx, cy = c
|
||||
for i=1:length(x)
|
||||
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
|
||||
@@ -238,9 +205,12 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
|
||||
end
|
||||
|
||||
"rotate an object in space"
|
||||
function rotate(shape::Shape, Θ::Real, c = center(shape))
|
||||
shapecopy = deepcopy(shape)
|
||||
rotate!(shapecopy, Θ, c)
|
||||
function rotate(shape::Shape, θ::Real, c = center(shape))
|
||||
x, y = coords(shape)
|
||||
cx, cy = c
|
||||
x_new = rotate_x.(x, y, θ, cx, cy)
|
||||
y_new = rotate_y.(x, y, θ, cx, cy)
|
||||
Shape(x_new, y_new)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
@@ -255,8 +225,24 @@ mutable struct Font
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
"Create a Font from a list of unordered features"
|
||||
function font(args...)
|
||||
"""
|
||||
font(args...)
|
||||
Create a Font from a list of features. Values may be specified either as
|
||||
arguments (which are distinguished by type/value) or as keyword arguments.
|
||||
# Arguments
|
||||
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
|
||||
- `pointsize`: Integer. Size of font in points
|
||||
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
|
||||
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
|
||||
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
|
||||
- `color`: Colorant or Symbol
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> font(8)
|
||||
julia> font(family="serif",halign=:center,rotation=45.0)
|
||||
```
|
||||
"""
|
||||
function font(args...;kw...)
|
||||
|
||||
# defaults
|
||||
family = "sans-serif"
|
||||
@@ -296,7 +282,33 @@ function font(args...)
|
||||
elseif typeof(arg) <: Real
|
||||
rotation = convert(Float64, arg)
|
||||
else
|
||||
warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
@warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
for symbol in keys(kw)
|
||||
if symbol == :family
|
||||
family = string(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
|
||||
|
||||
@@ -315,9 +327,15 @@ end
|
||||
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, :guidefontsize, :tickfontsize, :legendfontsize)
|
||||
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
|
||||
|
||||
"""
|
||||
@@ -326,15 +344,27 @@ end
|
||||
Resets font sizes to initial default values.
|
||||
"""
|
||||
function scalefontsizes()
|
||||
for k in (:titlefontsize, :guidefontsize, :tickfontsize, :legendfontsize)
|
||||
f = default(k)
|
||||
if k in keys(_initial_fontsizes)
|
||||
factor = f / _initial_fontsizes[k]
|
||||
scalefontsize(k, 1.0/factor)
|
||||
end
|
||||
end
|
||||
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
|
||||
@@ -343,15 +373,16 @@ end
|
||||
PlotText(str) = PlotText(string(str), font())
|
||||
|
||||
"""
|
||||
text(string, args...)
|
||||
text(string, args...; kw...)
|
||||
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations.
|
||||
`args` and `kw` are passed to `font`.
|
||||
"""
|
||||
text(t::PlotText) = t
|
||||
text(t::PlotText, font::Font) = PlotText(t.str, font)
|
||||
text(str::AbstractString, f::Font) = PlotText(str, f)
|
||||
function text(str, args...)
|
||||
PlotText(string(str), font(args...))
|
||||
function text(str, args...;kw...)
|
||||
PlotText(string(str), font(args...;kw...))
|
||||
end
|
||||
|
||||
Base.length(t::PlotText) = length(t.str)
|
||||
@@ -388,13 +419,14 @@ function stroke(args...; alpha = nothing)
|
||||
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)))")
|
||||
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -420,13 +452,14 @@ function brush(args...; alpha = nothing)
|
||||
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)))")
|
||||
@warn("Unused brush arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -438,16 +471,21 @@ end
|
||||
mutable struct SeriesAnnotations
|
||||
strs::AbstractVector # the labels/names
|
||||
font::Font
|
||||
baseshape::Nullable
|
||||
baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
|
||||
scalefactor::Tuple
|
||||
end
|
||||
|
||||
series_annotations(scalar) = series_annotations([scalar])
|
||||
function series_annotations(anns::AMat)
|
||||
map(series_annotations, anns)
|
||||
end
|
||||
function series_annotations(strs::AbstractVector, args...)
|
||||
fnt = font()
|
||||
shp = Nullable{Any}()
|
||||
shp = nothing
|
||||
scalefactor = (1,1)
|
||||
for arg in args
|
||||
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
|
||||
shp = Nullable(arg)
|
||||
shp = arg
|
||||
elseif isa(arg, Font)
|
||||
fnt = arg
|
||||
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
||||
@@ -457,7 +495,7 @@ function series_annotations(strs::AbstractVector, args...)
|
||||
elseif is_2tuple(arg)
|
||||
scalefactor = arg
|
||||
else
|
||||
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
# if scalefactor != 1
|
||||
@@ -468,7 +506,7 @@ function series_annotations(strs::AbstractVector, args...)
|
||||
SeriesAnnotations(strs, fnt, shp, scalefactor)
|
||||
end
|
||||
series_annotations(anns::SeriesAnnotations) = anns
|
||||
series_annotations(::Void) = nothing
|
||||
series_annotations(::Nothing) = nothing
|
||||
|
||||
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
anns = series[:series_annotations]
|
||||
@@ -483,12 +521,13 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
# end
|
||||
|
||||
# @show msw msh
|
||||
if anns != nothing && !isnull(anns.baseshape)
|
||||
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 = Shape[begin
|
||||
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)
|
||||
@@ -505,9 +544,9 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
# and then re-scale a copy of baseshape to match the w/h ratio
|
||||
maxscale = max(xscale, yscale)
|
||||
push!(msize, maxscale)
|
||||
baseshape = _cycle(get(anns.baseshape),i)
|
||||
shape = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
|
||||
end for i=1:length(anns.strs)]
|
||||
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
|
||||
@@ -519,9 +558,12 @@ mutable struct EachAnn
|
||||
x
|
||||
y
|
||||
end
|
||||
Base.start(ea::EachAnn) = 1
|
||||
Base.done(ea::EachAnn, i) = ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
|
||||
function Base.next(ea::EachAnn, i)
|
||||
|
||||
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
|
||||
@@ -531,30 +573,55 @@ function Base.next(ea::EachAnn, i)
|
||||
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
|
||||
end
|
||||
|
||||
annotations(::Void) = []
|
||||
annotations(::Nothing) = []
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns::AMat) = map(annotations, 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())
|
||||
function process_annotation(sp::Subplot, xs, ys, labs, font = nothing)
|
||||
anns = []
|
||||
labs = makevec(labs)
|
||||
for i in 1:max(length(xs), length(ys), length(labs))
|
||||
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
|
||||
xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs)
|
||||
ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys)
|
||||
if isnothing(font)
|
||||
font = Plots.font(;
|
||||
family=sp[:annotationfontfamily],
|
||||
pointsize=sp[:annotationfontsize],
|
||||
halign=sp[:annotationhalign],
|
||||
valign=sp[:annotationvalign],
|
||||
rotation=sp[:annotationrotation],
|
||||
color=sp[:annotationcolor],
|
||||
)
|
||||
end
|
||||
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 : text(lab, font)))
|
||||
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab[1], font, lab[2:end]...) : text(lab, font)))
|
||||
end
|
||||
end
|
||||
anns
|
||||
end
|
||||
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font())
|
||||
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = nothing)
|
||||
anns = []
|
||||
positions, labs = makevec(positions), makevec(labs)
|
||||
if isnothing(font)
|
||||
font = Plots.font(;
|
||||
family=sp[:annotationfontfamily],
|
||||
pointsize=sp[:annotationfontsize],
|
||||
halign=sp[:annotationhalign],
|
||||
valign=sp[:annotationvalign],
|
||||
rotation=sp[:annotationrotation],
|
||||
color=sp[:annotationcolor],
|
||||
)
|
||||
end
|
||||
for i in 1:max(length(positions), length(labs))
|
||||
pos, lab = _cycle(positions, i), _cycle(labs, i)
|
||||
pos = get(_positionAliases, pos, pos)
|
||||
@@ -562,12 +629,15 @@ function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol},
|
||||
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
|
||||
else
|
||||
push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font)))
|
||||
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab[1], font, lab[2:end]...) : 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}}(
|
||||
@@ -584,6 +654,7 @@ function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
|
||||
(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)"
|
||||
@@ -598,23 +669,6 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
abstract type AbstractSurface end
|
||||
|
||||
"represents a contour or surface mesh"
|
||||
struct Surface{M<:AMat} <: AbstractSurface
|
||||
surf::M
|
||||
end
|
||||
|
||||
Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for yi in y, xi in x])
|
||||
|
||||
Base.Array(surf::Surface) = surf.surf
|
||||
|
||||
for f in (:length, :size)
|
||||
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
|
||||
end
|
||||
Base.copy(surf::Surface) = Surface(copy(surf.surf))
|
||||
Base.eltype(surf::Surface{T}) where {T} = eltype(T)
|
||||
|
||||
function expand_extrema!(a::Axis, surf::Surface)
|
||||
ex = a[:extrema]
|
||||
for vi in surf.surf
|
||||
@@ -634,28 +688,7 @@ end
|
||||
# # I don't want to clash with ValidatedNumerics, but this would be nice:
|
||||
# ..(a::T, b::T) = (a,b)
|
||||
|
||||
struct Volume{T}
|
||||
v::Array{T,3}
|
||||
x_extents::Tuple{T,T}
|
||||
y_extents::Tuple{T,T}
|
||||
z_extents::Tuple{T,T}
|
||||
end
|
||||
|
||||
default_extents(::Type{T}) where {T} = (zero(T), one(T))
|
||||
|
||||
function Volume(v::Array{T,3},
|
||||
x_extents = default_extents(T),
|
||||
y_extents = default_extents(T),
|
||||
z_extents = default_extents(T)) where T
|
||||
Volume(v, x_extents, y_extents, z_extents)
|
||||
end
|
||||
|
||||
Base.Array(vol::Volume) = vol.v
|
||||
for f in (:length, :size)
|
||||
@eval Base.$f(vol::Volume, args...) = $f(vol.v, args...)
|
||||
end
|
||||
Base.copy(vol::Volume{T}) where {T} = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
|
||||
Base.eltype(vol::Volume{T}) where {T} = T
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
@@ -697,7 +730,7 @@ function arrow(args...)
|
||||
elseif T <: Tuple && length(arg) == 2
|
||||
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
|
||||
else
|
||||
warn("Skipped arrow arg $arg")
|
||||
@warn("Skipped arrow arg $arg")
|
||||
end
|
||||
end
|
||||
Arrow(style, side, headlength, headwidth)
|
||||
@@ -719,17 +752,9 @@ function add_arrows(func::Function, x::AVec, y::AVec)
|
||||
end
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"Represents data values with formatting that should apply to the tick labels."
|
||||
struct Formatted{T}
|
||||
data::T
|
||||
formatter::Function
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
"create a BezierCurve for plotting"
|
||||
mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
mutable struct BezierCurve{T <: GeometryBasics.Point}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
@@ -742,12 +767,9 @@ function (bc::BezierCurve)(t::Real)
|
||||
p
|
||||
end
|
||||
|
||||
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
|
||||
# mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
|
||||
|
||||
@deprecate curve_points coords
|
||||
|
||||
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
|
||||
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]
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
supported_attrs(::BokehBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:linecolor,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
# :linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
:size,
|
||||
:title,
|
||||
# :window_title,
|
||||
:x,
|
||||
# :xguide,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
:y,
|
||||
# :yguide,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface,
|
||||
# :levels,
|
||||
])
|
||||
supported_types(::BokehBackend) = [:path, :scatter]
|
||||
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::BokehBackend) = [:identity, :ln]
|
||||
is_subplot_supported(::BokehBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
function _initialize_backend(::BokehBackend; kw...)
|
||||
@eval begin
|
||||
warn("Bokeh is no longer supported... many features will likely be broken.")
|
||||
import Bokeh
|
||||
export Bokeh
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
const _glyphtypes = KW(
|
||||
:circle => :Circle,
|
||||
:rect => :Square,
|
||||
:diamond => :Diamond,
|
||||
:utriangle => :Triangle,
|
||||
:dtriangle => :InvertedTriangle,
|
||||
# :pentagon =>
|
||||
# :hexagon =>
|
||||
# :heptagon =>
|
||||
# :octagon =>
|
||||
:cross => :Cross,
|
||||
:xcross => :X,
|
||||
:star5 => :Asterisk,
|
||||
)
|
||||
|
||||
|
||||
function bokeh_glyph_type(d::KW)
|
||||
st = d[:seriestype]
|
||||
mt = d[:markershape]
|
||||
if st == :scatter && mt == :none
|
||||
mt = :circle
|
||||
end
|
||||
|
||||
# if we have a marker, use that
|
||||
if st == :scatter || mt != :none
|
||||
return _glyphtypes[mt]
|
||||
end
|
||||
|
||||
# otherwise return a line
|
||||
return :Line
|
||||
end
|
||||
|
||||
function get_stroke_vector(linestyle::Symbol)
|
||||
dash = 12
|
||||
dot = 3
|
||||
gap = 2
|
||||
linestyle == :solid && return Int[]
|
||||
linestyle == :dash && return Int[dash, gap]
|
||||
linestyle == :dot && return Int[dot, gap]
|
||||
linestyle == :dashdot && return Int[dash, gap, dot, gap]
|
||||
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
|
||||
error("unsupported linestyle: ", linestyle)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# function _create_plot(pkg::BokehBackend, d::KW)
|
||||
function _create_backend_figure(plt::Plot{BokehBackend})
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
|
||||
datacolumns = Bokeh.BokehDataSet[]
|
||||
tools = Bokeh.tools()
|
||||
filename = tempname() * ".html"
|
||||
title = plt.attr[:title]
|
||||
w, h = plt.attr[:size]
|
||||
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
|
||||
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
|
||||
# legend = plt.attr[:legend] ? xxxx : nothing
|
||||
legend = nothing
|
||||
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
|
||||
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
|
||||
|
||||
# Plot(bplt, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
# function _series_added(::BokehBackend, plt::Plot, d::KW)
|
||||
function _series_added(plt::Plot{BokehBackend}, series::Series)
|
||||
bdata = Dict{Symbol, Vector}(:x => collect(series.d[:x]), :y => collect(series.d[:y]))
|
||||
|
||||
glyph = Bokeh.Bokehjs.Glyph(
|
||||
glyphtype = bokeh_glyph_type(d),
|
||||
linecolor = webcolor(d[:linecolor]), # shape's stroke or line color
|
||||
linewidth = d[:linewidth], # shape's stroke width or line width
|
||||
fillcolor = webcolor(d[:markercolor]),
|
||||
size = ceil(Int, d[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
|
||||
dash = get_stroke_vector(d[:linestyle])
|
||||
)
|
||||
|
||||
legend = nothing # TODO
|
||||
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
|
||||
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot_object(plt::Plot{BokehBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
# function getxy(plt::Plot{BokehBackend}, i::Int)
|
||||
# series = plt.o.datacolumns[i].data
|
||||
# series[:x], series[:y]
|
||||
# end
|
||||
#
|
||||
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
|
||||
# series = plt.o.datacolumns[i].data
|
||||
# series[:x], series[:y] = xy
|
||||
# plt
|
||||
# end
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
|
||||
# TODO: write a png to io
|
||||
warn("mime png not implemented")
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
|
||||
Bokeh.showplot(plt.o)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
|
||||
# # TODO: display/show the subplot
|
||||
# end
|
||||
@@ -1,744 +0,0 @@
|
||||
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
|
||||
supported_attrs(::GadflyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
:group, :label, :seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :n, :nc, :nr, :layout, :smooth,
|
||||
:title, :window_title, :show, :size,
|
||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
|
||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
|
||||
:z,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
])
|
||||
supported_types(::GadflyBackend) = [
|
||||
:path,
|
||||
:scatter, :hexbin,
|
||||
:bar,
|
||||
:contour, :shape
|
||||
]
|
||||
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
is_subplot_supported(::GadflyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::GadflyBackend; kw...)
|
||||
@eval begin
|
||||
import Gadfly, Compose
|
||||
export Gadfly, Compose
|
||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# immutable MissingVec <: AbstractVector{Float64} end
|
||||
# Base.size(v::MissingVec) = (1,)
|
||||
# Base.getindex(v::MissingVec, i::Integer) = 0.0
|
||||
|
||||
function createGadflyPlotObject(d::KW)
|
||||
gplt = Gadfly.Plot()
|
||||
gplt.mapping = Dict()
|
||||
gplt.data_source = Gadfly.DataFrames.DataFrame()
|
||||
# gplt.layers = gplt.layers[1:0]
|
||||
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
|
||||
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xguide]),
|
||||
Gadfly.Guide.ylabel(d[:yguide]),
|
||||
Gadfly.Guide.title(d[:title])]
|
||||
gplt
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function getLineGeom(d::KW)
|
||||
st = d[:seriestype]
|
||||
xbins, ybins = maketuple(d[:bins])
|
||||
if st == :hexb
|
||||
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
|
||||
elseif st == :histogram2d
|
||||
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
|
||||
elseif st == :histogram
|
||||
Gadfly.Geom.histogram(bincount = xbins,
|
||||
orientation = isvertical(d) ? :vertical : :horizontal,
|
||||
position = d[:bar_position] == :stack ? :stack : :dodge)
|
||||
elseif st == :path
|
||||
Gadfly.Geom.path
|
||||
elseif st in (:bar, :sticks)
|
||||
Gadfly.Geom.bar
|
||||
elseif st == :steppost
|
||||
Gadfly.Geom.step
|
||||
elseif st == :steppre
|
||||
Gadfly.Geom.step(direction = :vh)
|
||||
elseif st == :hline
|
||||
Gadfly.Geom.hline
|
||||
elseif st == :vline
|
||||
Gadfly.Geom.vline
|
||||
elseif st == :contour
|
||||
Gadfly.Geom.contour(levels = d[:levels])
|
||||
# elseif st == :shape
|
||||
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
||||
else
|
||||
nothing
|
||||
end
|
||||
end
|
||||
|
||||
function get_extra_theme_args(d::KW, k::Symbol)
|
||||
# gracefully handles old Gadfly versions
|
||||
extra_theme_args = KW()
|
||||
try
|
||||
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k])
|
||||
catch err
|
||||
if string(err) == "UndefVarError(:get_stroke_vector)"
|
||||
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
|
||||
else
|
||||
rethrow()
|
||||
end
|
||||
end
|
||||
extra_theme_args
|
||||
end
|
||||
|
||||
function getGadflyLineTheme(d::KW)
|
||||
st = d[:seriestype]
|
||||
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
|
||||
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
|
||||
|
||||
Gadfly.Theme(;
|
||||
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
|
||||
line_width = (st == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
|
||||
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
|
||||
lowlight_color = x->RGB(fc), # fill/ribbon
|
||||
lowlight_opacity = alpha(fc), # fill/ribbon
|
||||
bar_highlight = RGB(lc), # bars
|
||||
get_extra_theme_args(d, :linestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
# add a line as a new layer
|
||||
function addGadflyLine!(plt::Plot, numlayers::Int, d::KW, geoms...)
|
||||
gplt = getGadflyContext(plt)
|
||||
gfargs = vcat(geoms..., getGadflyLineTheme(d))
|
||||
kwargs = KW()
|
||||
st = d[:seriestype]
|
||||
|
||||
# add a fill?
|
||||
if d[:fillrange] != nothing && st != :contour
|
||||
fillmin, fillmax = map(makevec, maketuple(d[:fillrange]))
|
||||
nmin, nmax = length(fillmin), length(fillmax)
|
||||
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
|
||||
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
|
||||
push!(gfargs, Gadfly.Geom.ribbon)
|
||||
end
|
||||
|
||||
if st in (:hline, :vline)
|
||||
kwargs[st == :hline ? :yintercept : :xintercept] = d[:y]
|
||||
|
||||
else
|
||||
if st == :sticks
|
||||
w = 0.01 * mean(diff(d[:x]))
|
||||
kwargs[:xmin] = d[:x] - w
|
||||
kwargs[:xmax] = d[:x] + w
|
||||
elseif st == :contour
|
||||
kwargs[:z] = d[:z].surf
|
||||
addGadflyContColorScale(plt, d[:linecolor])
|
||||
end
|
||||
|
||||
kwargs[:x] = d[st == :histogram ? :y : :x]
|
||||
kwargs[:y] = d[:y]
|
||||
|
||||
end
|
||||
|
||||
# # add the layer
|
||||
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
get_shape(sym::Symbol) = _shapes[sym]
|
||||
get_shape(shape::Shape) = shape
|
||||
|
||||
# extract the underlying ShapeGeometry object(s)
|
||||
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
|
||||
getMarkerGeom(other) = gadflyshape(get_shape(other))
|
||||
|
||||
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
|
||||
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
|
||||
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
|
||||
function getMarkerGeom(d::KW)
|
||||
if d[:seriestype] == :shape
|
||||
Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
||||
else
|
||||
getMarkerGeom(d[:markershape])
|
||||
end
|
||||
end
|
||||
|
||||
function getGadflyMarkerTheme(d::KW, attr::KW)
|
||||
c = getColor(d[:markercolor])
|
||||
α = d[:markeralpha]
|
||||
if α != nothing
|
||||
c = RGBA(RGB(c), α)
|
||||
end
|
||||
|
||||
ms = d[:markersize]
|
||||
ms = if typeof(ms) <: AVec
|
||||
warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
|
||||
mean(ms) * Gadfly.px
|
||||
else
|
||||
ms * Gadfly.px
|
||||
end
|
||||
|
||||
Gadfly.Theme(;
|
||||
default_color = c,
|
||||
default_point_size = ms,
|
||||
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
|
||||
highlight_width = d[:markerstrokewidth] * Gadfly.px,
|
||||
line_width = d[:markerstrokewidth] * Gadfly.px,
|
||||
# get_extra_theme_args(d, :markerstrokestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
|
||||
plt.attr[:colorbar] == :none && return
|
||||
if !isa(c, ColorGradient)
|
||||
c = default_gradient()
|
||||
end
|
||||
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
|
||||
end
|
||||
|
||||
function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, attr::KW, geoms...)
|
||||
gfargs = vcat(geoms..., getGadflyMarkerTheme(d, attr), getMarkerGeom(d))
|
||||
kwargs = KW()
|
||||
|
||||
# handle continuous color scales for the markers
|
||||
zcolor = d[:marker_z]
|
||||
if zcolor != nothing && typeof(zcolor) <: AVec
|
||||
kwargs[:color] = zcolor
|
||||
addGadflyContColorScale(plt, d[:markercolor])
|
||||
end
|
||||
|
||||
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function addToGadflyLegend(plt::Plot, d::KW)
|
||||
if plt.attr[:legend] != :none && d[:label] != ""
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add the legend if needed
|
||||
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
|
||||
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
|
||||
end
|
||||
|
||||
# now add the series to the legend
|
||||
for guide in gplt.guides
|
||||
if isa(guide, Gadfly.Guide.ManualColorKey)
|
||||
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
|
||||
# since gadfly will call unique(colors), but doesn't also merge the rows that match
|
||||
# Should ensure from this side that colors which are the same are merged together
|
||||
|
||||
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
|
||||
foundit = false
|
||||
|
||||
# extend the label if we found this color
|
||||
for i in 1:length(guide.colors)
|
||||
if RGB(c) == guide.colors[i]
|
||||
guide.labels[i] *= ", " * d[:label]
|
||||
foundit = true
|
||||
end
|
||||
end
|
||||
|
||||
# didn't find the color, so add a new entry into the legend
|
||||
if !foundit
|
||||
push!(guide.labels, d[:label])
|
||||
push!(guide.colors, c)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
|
||||
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
|
||||
|
||||
|
||||
function addGadflySeries!(plt::Plot, d::KW)
|
||||
layers = Gadfly.Layer[]
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add a regression line?
|
||||
# TODO: make more flexible
|
||||
smooth = getGadflySmoothing(d[:smooth])
|
||||
|
||||
# lines
|
||||
geom = getLineGeom(d)
|
||||
if geom != nothing
|
||||
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
|
||||
smooth = Any[] # don't add a regression for markers too
|
||||
end
|
||||
|
||||
# special handling for ohlc and scatter
|
||||
st = d[:seriestype]
|
||||
# if st == :ohlc
|
||||
# error("Haven't re-implemented after refactoring")
|
||||
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
|
||||
elseif st == :scatter && d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# markers
|
||||
if d[:markershape] != :none || st == :shape
|
||||
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.attr, smooth...))
|
||||
end
|
||||
|
||||
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, d)
|
||||
|
||||
# now save the layers that apply to this series
|
||||
d[:gadflylayers] = layers
|
||||
prepend!(gplt.layers, layers)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
|
||||
|
||||
# # colorgroup
|
||||
# z = d[:z]
|
||||
|
||||
# # handle line segments of different colors
|
||||
# cscheme = d[:linecolor]
|
||||
# if isa(cscheme, ColorVector)
|
||||
# # create a color scale, and set the color group to the index of the color
|
||||
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
|
||||
|
||||
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
|
||||
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
|
||||
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
|
||||
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(d[:y])]
|
||||
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
|
||||
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
|
||||
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
|
||||
# colorgroup = [(:linecolor, cs), (:group, grp)]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
|
||||
ticks == :auto && return
|
||||
|
||||
# remove the ticks?
|
||||
if ticks in (:none, false, nothing)
|
||||
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
end
|
||||
|
||||
ttype = ticksType(ticks)
|
||||
|
||||
# just the values... put ticks here, but use standard labels
|
||||
if ttype == :ticks
|
||||
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
|
||||
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
|
||||
|
||||
# set the ticks and the labels
|
||||
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
|
||||
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
|
||||
elseif ttype == :ticks_and_labels
|
||||
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
|
||||
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
|
||||
|
||||
# # TODO add xtick_label function (given tick, return label??)
|
||||
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
|
||||
# filterGadflyScale(gplt, isx)
|
||||
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
|
||||
# labelmap = Dict(zip(ticks...))
|
||||
# labelfunc = val -> labelmap[val]
|
||||
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
|
||||
|
||||
filterGadflyScale(gplt, isx)
|
||||
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
|
||||
labelmap = Dict(zip(ticks...))
|
||||
labelfunc = val -> labelmap[val]
|
||||
push!(gplt.scales, gfunc(labels = labelfunc))
|
||||
|
||||
else
|
||||
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
|
||||
end
|
||||
end
|
||||
|
||||
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
|
||||
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
|
||||
|
||||
|
||||
function getGadflyScaleFunction(d::KW, isx::Bool)
|
||||
scalekey = isx ? :xscale : :yscale
|
||||
hasScaleKey = haskey(d, scalekey)
|
||||
if hasScaleKey
|
||||
scale = d[scalekey]
|
||||
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
|
||||
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
|
||||
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
|
||||
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
|
||||
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
|
||||
end
|
||||
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
|
||||
end
|
||||
|
||||
|
||||
function addGadflyLimitsScale(gplt, d::KW, isx::Bool)
|
||||
gfunc, hasScaleKey, func = getGadflyScaleFunction(d, isx)
|
||||
|
||||
# do we want to add min/max limits for the axis?
|
||||
limsym = isx ? :xlims : :ylims
|
||||
limargs = Any[]
|
||||
|
||||
# map :auto to nothing, otherwise add to limargs
|
||||
lims = get(d, limsym, :auto)
|
||||
if lims == :auto
|
||||
lims = nothing
|
||||
else
|
||||
if limsType(lims) == :limits
|
||||
push!(limargs, (:minvalue, min(lims...)))
|
||||
push!(limargs, (:maxvalue, max(lims...)))
|
||||
else
|
||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
||||
end
|
||||
end
|
||||
|
||||
# replace any current scales with this one
|
||||
if hasScaleKey || !isempty(limargs)
|
||||
filterGadflyScale(gplt, isx)
|
||||
push!(gplt.scales, gfunc(; limargs...))
|
||||
end
|
||||
|
||||
lims, func
|
||||
end
|
||||
|
||||
function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
|
||||
if isa(gplt.coord, Gadfly.Coord.Cartesian)
|
||||
gplt.coord = Gadfly.Coord.cartesian(
|
||||
gplt.coord.xvars,
|
||||
gplt.coord.yvars;
|
||||
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
|
||||
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
|
||||
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
|
||||
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
|
||||
xflip = get(d, :xflip, gplt.coord.xflip),
|
||||
yflip = get(d, :yflip, gplt.coord.yflip),
|
||||
fixed = gplt.coord.fixed,
|
||||
aspect_ratio = gplt.coord.aspect_ratio,
|
||||
raster = gplt.coord.raster
|
||||
)
|
||||
else
|
||||
gplt.coord = Gadfly.Coord.Cartesian(
|
||||
xflip = get(d, :xflip, false),
|
||||
yflip = get(d, :yflip, false)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function findGuideAndSet(gplt, t::DataType, args...; kw...)
|
||||
for (i,guide) in enumerate(gplt.guides)
|
||||
if isa(guide, t)
|
||||
gplt.guides[i] = t(args...; kw...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function updateGadflyGuides(plt::Plot, d::KW)
|
||||
gplt = getGadflyContext(plt)
|
||||
haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title]))
|
||||
haskey(d, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xguide]))
|
||||
haskey(d, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:yguide]))
|
||||
|
||||
xlims, xfunc = addGadflyLimitsScale(gplt, d, true)
|
||||
ylims, yfunc = addGadflyLimitsScale(gplt, d, false)
|
||||
|
||||
ticks = get(d, :xticks, :auto)
|
||||
if ticks == :none
|
||||
_remove_axis(plt, true)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, true)
|
||||
end
|
||||
ticks = get(d, :yticks, :auto)
|
||||
if ticks == :none
|
||||
_remove_axis(plt, false)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, false)
|
||||
end
|
||||
|
||||
updateGadflyAxisFlips(gplt, d, xlims, ylims, xfunc, yfunc)
|
||||
end
|
||||
|
||||
function updateGadflyPlotTheme(plt::Plot, d::KW)
|
||||
kwargs = KW()
|
||||
|
||||
# colors
|
||||
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
|
||||
map(s -> getColor(d[s]), (
|
||||
:background_color_inside,
|
||||
:foreground_color_grid,
|
||||
:foreground_color_text,
|
||||
:foreground_color_guide,
|
||||
:foreground_color_legend
|
||||
))
|
||||
|
||||
# # hide the legend?
|
||||
leg = d[d[:legend] == :none ? :colorbar : :legend]
|
||||
if leg != :best
|
||||
kwargs[:key_position] = leg == :inside ? :right : leg
|
||||
end
|
||||
|
||||
if !get(d, :grid, true)
|
||||
kwargs[:grid_color] = gridcolor
|
||||
end
|
||||
|
||||
# fonts
|
||||
tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont]
|
||||
|
||||
getGadflyContext(plt).theme = Gadfly.Theme(;
|
||||
background_color = insidecolor,
|
||||
minor_label_color = textcolor,
|
||||
minor_label_font = tfont.family,
|
||||
minor_label_font_size = tfont.pointsize * Gadfly.pt,
|
||||
major_label_color = guidecolor,
|
||||
major_label_font = gfont.family,
|
||||
major_label_font_size = gfont.pointsize * Gadfly.pt,
|
||||
key_title_color = guidecolor,
|
||||
key_title_font = gfont.family,
|
||||
key_title_font_size = gfont.pointsize * Gadfly.pt,
|
||||
key_label_color = legendcolor,
|
||||
key_label_font = lfont.family,
|
||||
key_label_font_size = lfont.pointsize * Gadfly.pt,
|
||||
plot_padding = 1 * Gadfly.mm,
|
||||
kwargs...
|
||||
)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function createGadflyAnnotationObject(x, y, val::AbstractString)
|
||||
Gadfly.Guide.annotation(Compose.compose(
|
||||
Compose.context(),
|
||||
Compose.text(x, y, val)
|
||||
))
|
||||
end
|
||||
|
||||
function createGadflyAnnotationObject(x, y, txt::PlotText)
|
||||
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
|
||||
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
|
||||
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
|
||||
Gadfly.Guide.annotation(Compose.compose(
|
||||
Compose.context(),
|
||||
Compose.text(x, y, txt.str, halign, valign, rotations...),
|
||||
Compose.font(string(txt.font.family)),
|
||||
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
|
||||
Compose.stroke(txt.font.color),
|
||||
Compose.fill(txt.font.color)
|
||||
))
|
||||
end
|
||||
|
||||
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
# function _create_plot(pkg::GadflyBackend, d::KW)
|
||||
# gplt = createGadflyPlotObject(d)
|
||||
# Plot(gplt, pkg, 0, d, KW[])
|
||||
# end
|
||||
function _create_backend_figure(plt::Plot{GadflyBackend})
|
||||
createGadflyPlotObject(plt.attr)
|
||||
end
|
||||
|
||||
|
||||
# plot one data series
|
||||
# function _series_added(::GadflyBackend, plt::Plot, d::KW)
|
||||
function _series_added(plt::Plot{GadflyBackend}, series::Series)
|
||||
# first clear out the temporary layer
|
||||
gplt = getGadflyContext(plt)
|
||||
if gplt.layers[1].geom.tag == :remove
|
||||
gplt.layers = gplt.layers[2:end]
|
||||
end
|
||||
|
||||
addGadflySeries!(plt, series.d)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{GadflyBackend}, d::KW)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
# TODO: need to save all the layer indices which apply to this series
|
||||
function getGadflyMappings(plt::Plot, i::Integer)
|
||||
@assert i > 0 && i <= plt.n
|
||||
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
|
||||
end
|
||||
|
||||
function getxy(plt::Plot{GadflyBackend}, i::Integer)
|
||||
mapping = getGadflyMappings(plt, i)[1]
|
||||
mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
for mapping in getGadflyMappings(plt, i)
|
||||
mapping[:x], mapping[:y] = xy
|
||||
end
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# # create the underlying object (each backend will do this differently)
|
||||
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
|
||||
# isbefore && return false # wait until after plotting to create the subplots
|
||||
# subplt.o = nothing
|
||||
# true
|
||||
# end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
|
||||
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
|
||||
|
||||
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
|
||||
# function buildGadflySubplotContext(subplt::Subplot)
|
||||
# rows = Any[]
|
||||
# row = Any[]
|
||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
||||
#
|
||||
# # add the Plot object to the row
|
||||
# push!(row, getGadflyContext(subplt.plts[i]))
|
||||
#
|
||||
# # add the row
|
||||
# if c == ncols(subplt.layout, r)
|
||||
# push!(rows, Gadfly.hstack(row...))
|
||||
# row = Any[]
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # stack the rows
|
||||
# Gadfly.vstack(rows...)
|
||||
# end
|
||||
|
||||
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
|
||||
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
|
||||
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
|
||||
gplt = getGadflyContext(plt)
|
||||
setGadflyDisplaySize(plt)
|
||||
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
|
||||
end
|
||||
|
||||
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
|
||||
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
|
||||
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
|
||||
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
|
||||
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
|
||||
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
|
||||
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
|
||||
|
||||
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
|
||||
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
|
||||
func = getGadflyWriteFunc($mime())
|
||||
doshow(io, func, plt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
|
||||
setGadflyDisplaySize(plt.attr[:size]...)
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
|
||||
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
|
||||
# ctx = buildGadflySubplotContext(subplt)
|
||||
#
|
||||
# # taken from Gadfly since I couldn't figure out how to do it directly
|
||||
#
|
||||
# filename = string(Gadfly.tempname(), ".html")
|
||||
# output = open(filename, "w")
|
||||
#
|
||||
# plot_output = IOBuffer()
|
||||
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
|
||||
# Compose.default_graphic_height, false), ctx)
|
||||
# plotsvg = takebuf_string(plot_output)
|
||||
#
|
||||
# write(output,
|
||||
# """
|
||||
# <!DOCTYPE html>
|
||||
# <html>
|
||||
# <head>
|
||||
# <title>Gadfly Plot</title>
|
||||
# <meta charset="utf-8">
|
||||
# </head>
|
||||
# <body>
|
||||
# <script charset="utf-8">
|
||||
# $(readall(Compose.snapsvgjs))
|
||||
# </script>
|
||||
# <script charset="utf-8">
|
||||
# $(readall(Gadfly.gadflyjs))
|
||||
# </script>
|
||||
# $(plotsvg)
|
||||
# </body>
|
||||
# </html>
|
||||
# """)
|
||||
# close(output)
|
||||
# Gadfly.open_file(filename)
|
||||
# end
|
||||
@@ -1,93 +0,0 @@
|
||||
|
||||
|
||||
# Geometry which displays arbitrary shapes at given (x, y) positions.
|
||||
# note: vertices is a list of shapes
|
||||
struct ShapeGeometry <: Gadfly.GeometryElement
|
||||
vertices::AbstractVector #{Tuple{Float64,Float64}}
|
||||
tag::Symbol
|
||||
|
||||
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
|
||||
new(shape, tag)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: add for PR
|
||||
# const shape = ShapeGeometry
|
||||
|
||||
|
||||
function Gadfly.element_aesthetics(::ShapeGeometry)
|
||||
[:x, :y, :size, :color]
|
||||
end
|
||||
|
||||
|
||||
# Generate a form for a shape geometry.
|
||||
#
|
||||
# Args:
|
||||
# geom: shape geometry.
|
||||
# theme: the plot's theme.
|
||||
# aes: aesthetics.
|
||||
#
|
||||
# Returns:
|
||||
# A compose Form.
|
||||
#
|
||||
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
|
||||
|
||||
# TODO: add for PR
|
||||
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
|
||||
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
|
||||
# element_aesthetics(geom)...)
|
||||
|
||||
default_aes = Gadfly.Aesthetics()
|
||||
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
|
||||
default_aes.size = Compose.Measure[theme.default_point_size]
|
||||
aes = Gadfly.inherit(aes, default_aes)
|
||||
|
||||
lw_hover_scale = 10
|
||||
lw_ratio = theme.line_width / aes.size[1]
|
||||
|
||||
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
|
||||
|
||||
ctx = Compose.compose!(
|
||||
Compose.context(),
|
||||
make_polygon(geom, aes.x, aes.y, aes.size),
|
||||
Compose.fill(aes.color),
|
||||
Compose.linewidth(theme.highlight_width))
|
||||
|
||||
if aes.color_key_continuous != nothing && aes.color_key_continuous
|
||||
Compose.compose!(ctx,
|
||||
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
|
||||
else
|
||||
Compose.compose!(ctx,
|
||||
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
|
||||
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
|
||||
for c in aes.color]))
|
||||
end
|
||||
|
||||
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
|
||||
end
|
||||
|
||||
function gadflyshape(sv::Shape)
|
||||
ShapeGeometry(Any[vertices(sv)])
|
||||
end
|
||||
|
||||
function gadflyshape(sv::AVec{Shape})
|
||||
ShapeGeometry(Any[vertices(s) for s in sv])
|
||||
end
|
||||
|
||||
|
||||
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
|
||||
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
|
||||
n = max(length(xs), length(ys), length(rs))
|
||||
T = Tuple{Compose.Measure, Compose.Measure}
|
||||
polys = Array(Vector{T}, n)
|
||||
for i in 1:n
|
||||
x = Compose.x_measure(xs[mod1(i, length(xs))])
|
||||
y = Compose.y_measure(ys[mod1(i, length(ys))])
|
||||
r = rs[mod1(i, length(rs))]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
|
||||
end
|
||||
Gadfly.polygon(polys, geom.tag)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
@@ -1,186 +0,0 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
supported_attrs(::ImmerseBackend) = supported_attrs(GadflyBackend())
|
||||
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
|
||||
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
|
||||
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
|
||||
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
|
||||
is_subplot_supported(::ImmerseBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::ImmerseBackend; kw...)
|
||||
@eval begin
|
||||
import Immerse, Gadfly, Compose, Gtk
|
||||
export Immerse, Gadfly, Compose, Gtk
|
||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
function createImmerseFigure(d::KW)
|
||||
w,h = d[:size]
|
||||
figidx = Immerse.figure(; name = d[:window_title], width = w, height = h)
|
||||
Immerse.Figure(figidx)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
# function _create_plot(pkg::ImmerseBackend, d::KW)
|
||||
# # create the underlying Gadfly.Plot object
|
||||
# gplt = createGadflyPlotObject(d)
|
||||
#
|
||||
# # save both the Immerse.Figure and the Gadfly.Plot
|
||||
# Plot((nothing,gplt), pkg, 0, d, KW[])
|
||||
# end
|
||||
function _create_backend_figure(plt::Plot{ImmerseBackend})
|
||||
(nothing, createGadflyPlotObject(plt.attr))
|
||||
end
|
||||
|
||||
|
||||
# # plot one data series
|
||||
# function _series_added(::ImmerseBackend, plt::Plot, d::KW)
|
||||
# addGadflySeries!(plt, d)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
# end
|
||||
|
||||
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
|
||||
addGadflySeries!(plt, series.d)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{ImmerseBackend}, d::KW)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
|
||||
mapping = getGadflyMappings(plt, i)[1]
|
||||
mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
for mapping in getGadflyMappings(plt, i)
|
||||
mapping[:x], mapping[:y] = xy
|
||||
end
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
|
||||
# return false
|
||||
# # isbefore && return false
|
||||
# end
|
||||
#
|
||||
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
|
||||
# # create the Gtk window with vertical box vsep
|
||||
# d = getattr(subplt,1)
|
||||
# w,h = d[:size]
|
||||
# vsep = Gtk.GtkBoxLeaf(:v)
|
||||
# win = Gtk.GtkWindowLeaf(vsep, d[:window_title], w, h)
|
||||
#
|
||||
# figindices = []
|
||||
# row = Gtk.GtkBoxLeaf(:h)
|
||||
# push!(vsep, row)
|
||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
||||
# plt = subplt.plts[i]
|
||||
#
|
||||
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
|
||||
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
|
||||
#
|
||||
# # add the plot's box to the row
|
||||
# push!(row, box)
|
||||
#
|
||||
# # create the figure and store the index returned for destruction later
|
||||
# figidx = Immerse.figure(canvas)
|
||||
# push!(figindices, figidx)
|
||||
#
|
||||
# fig = Immerse.figure(figidx)
|
||||
# plt.o = (fig, plt.o[2])
|
||||
#
|
||||
# # add the row
|
||||
# if c == ncols(subplt.layout, r)
|
||||
# row = Gtk.GtkBoxLeaf(:h)
|
||||
# push!(vsep, row)
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# # destructor... clean up plots
|
||||
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
|
||||
#
|
||||
# subplt.o = win
|
||||
# true
|
||||
# end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
|
||||
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
|
||||
|
||||
fig, gplt = plt.o
|
||||
if fig == nothing
|
||||
fig = createImmerseFigure(plt.attr)
|
||||
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
|
||||
plt.o = (fig, gplt)
|
||||
end
|
||||
|
||||
Immerse.figure(fig.figno; displayfig = false)
|
||||
display(gplt)
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
|
||||
#
|
||||
# # if we haven't created the window yet, do it
|
||||
# if subplt.o == nothing
|
||||
# showSubplotObject(subplt)
|
||||
# end
|
||||
#
|
||||
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
|
||||
# for plt in subplt.plts
|
||||
# fig, gplt = plt.o
|
||||
# Immerse.figure(fig.figno; displayfig = false)
|
||||
# display(gplt)
|
||||
# end
|
||||
#
|
||||
# # o is the window... show it
|
||||
# showall(subplt.o)
|
||||
# end
|
||||
@@ -1,308 +0,0 @@
|
||||
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
|
||||
supported_attrs(::QwtBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:linecolor,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:bins,
|
||||
:pos,
|
||||
:title,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale,
|
||||
])
|
||||
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
|
||||
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supported_scales(::QwtBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::QwtBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::QwtBackend; kw...)
|
||||
@eval begin
|
||||
warn("Qwt is no longer supported... many features will likely be broken.")
|
||||
import Qwt
|
||||
export Qwt
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
const _qwtAliases = KW(
|
||||
:bins => :heatmap_n,
|
||||
:fillrange => :fillto,
|
||||
:linewidth => :width,
|
||||
:markershape => :marker,
|
||||
:hexbin => :heatmap,
|
||||
:path => :line,
|
||||
:steppost => :step,
|
||||
:steppre => :stepinverted,
|
||||
:star5 => :star1,
|
||||
:star8 => :star2,
|
||||
)
|
||||
|
||||
function fixcolors(d::KW)
|
||||
for (k,v) in d
|
||||
if typeof(v) <: ColorScheme
|
||||
d[k] = getColor(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function replaceQwtAliases(d, s)
|
||||
if haskey(_qwtAliases, d[s])
|
||||
d[s] = _qwtAliases[d[s]]
|
||||
end
|
||||
end
|
||||
|
||||
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
||||
d = KW(kw)
|
||||
st = d[:seriestype]
|
||||
if st == :scatter
|
||||
d[:seriestype] = :none
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
elseif st in (:hline, :vline)
|
||||
addLineMarker(plt, d)
|
||||
d[:seriestype] = :none
|
||||
d[:markershape] = :circle
|
||||
d[:markersize] = 1
|
||||
if st == :vline
|
||||
d[:x], d[:y] = d[:y], d[:x]
|
||||
end
|
||||
|
||||
elseif !iscreating && st == :bar
|
||||
d = barHack(; kw...)
|
||||
elseif !iscreating && st == :histogram
|
||||
d = barHack(; histogramHack(; kw...)...)
|
||||
end
|
||||
|
||||
replaceQwtAliases(d, :seriestype)
|
||||
replaceQwtAliases(d, :markershape)
|
||||
|
||||
for k in keys(d)
|
||||
if haskey(_qwtAliases, k)
|
||||
d[_qwtAliases[k]] = d[k]
|
||||
end
|
||||
end
|
||||
|
||||
d[:x] = collect(d[:x])
|
||||
d[:y] = collect(d[:y])
|
||||
|
||||
d
|
||||
end
|
||||
|
||||
# function _create_plot(pkg::QwtBackend, d::KW)
|
||||
function _create_backend_figure(plt::Plot{QwtBackend})
|
||||
fixcolors(plt.attr)
|
||||
dumpdict(plt.attr,"\n\n!!! plot")
|
||||
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
|
||||
# plt = Plot(o, pkg, 0, d, KW[])
|
||||
# plt
|
||||
end
|
||||
|
||||
# function _series_added(::QwtBackend, plt::Plot, d::KW)
|
||||
function _series_added(plt::Plot{QwtBackend}, series::Series)
|
||||
d = adjustQwtKeywords(plt, false; series.d...)
|
||||
fixcolors(d)
|
||||
dumpdict(d,"\n\n!!! plot!")
|
||||
Qwt.oplot(plt.o; d...)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
|
||||
lims = get(d, isx ? :xlims : :ylims, nothing)
|
||||
ticks = get(d, isx ? :xticks : :yticks, nothing)
|
||||
w = plt.o.widget
|
||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
||||
|
||||
if typeof(lims) <: Union{Tuple,AVec} && length(lims) == 2
|
||||
if isx
|
||||
plt.o.autoscale_x = false
|
||||
else
|
||||
plt.o.autoscale_y = false
|
||||
end
|
||||
w[:setAxisScale](axisid, lims...)
|
||||
end
|
||||
|
||||
if typeof(ticks) <: Range
|
||||
if isx
|
||||
plt.o.autoscale_x = false
|
||||
else
|
||||
plt.o.autoscale_y = false
|
||||
end
|
||||
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
|
||||
elseif !(ticks in (nothing, :none, :auto))
|
||||
warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
|
||||
end
|
||||
|
||||
# change the scale
|
||||
scalesym = isx ? :xscale : :yscale
|
||||
if haskey(d, scalesym)
|
||||
scaletype = d[scalesym]
|
||||
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
|
||||
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
|
||||
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
|
||||
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
|
||||
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{QwtBackend}, d::KW)
|
||||
haskey(d, :title) && Qwt.title(plt.o, d[:title])
|
||||
haskey(d, :xguide) && Qwt.xlabel(plt.o, d[:xguide])
|
||||
haskey(d, :yguide) && Qwt.ylabel(plt.o, d[:yguide])
|
||||
updateLimsAndTicks(plt, d, true)
|
||||
updateLimsAndTicks(plt, d, false)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, d::KW)
|
||||
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
|
||||
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
|
||||
function addLineMarker(plt::Plot{QwtBackend}, d::KW)
|
||||
for yi in d[:y]
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
ishorizontal = (d[:seriestype] == :hline)
|
||||
marker[:setLineStyle](ishorizontal ? 1 : 2)
|
||||
marker[ishorizontal ? :setYValue : :setXValue](yi)
|
||||
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
|
||||
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
|
||||
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
# marker[:setValue](x, y)
|
||||
# marker[:setLabel](Qwt.QWT.QwtText(val))
|
||||
# marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
marker[:setValue](x, y)
|
||||
qwttext = Qwt.QWT.QwtText(val.str)
|
||||
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
|
||||
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
|
||||
marker[:setLabel](qwttext)
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
marker[:setValue](x, y)
|
||||
marker[:setLabel](Qwt.QWT.QwtText(val))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
createQwtAnnotation(plt, ann...)
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function getxy(plt::Plot{QwtBackend}, i::Int)
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y = xy
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# # create the underlying object (each backend will do this differently)
|
||||
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
|
||||
# isbefore && return false
|
||||
# i = 0
|
||||
# rows = Any[]
|
||||
# row = Any[]
|
||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
||||
# push!(row, subplt.plts[i].o)
|
||||
# if c == ncols(subplt.layout, r)
|
||||
# push!(rows, Qwt.hsplitter(row...))
|
||||
# row = Any[]
|
||||
# end
|
||||
# end
|
||||
# # for rowcnt in subplt.layout.rowcounts
|
||||
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
|
||||
# # i += rowcnt
|
||||
# # end
|
||||
# subplt.o = Qwt.vsplitter(rows...)
|
||||
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
|
||||
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
|
||||
# true
|
||||
# end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
|
||||
for series in plt.o.lines
|
||||
_expand_limits(lims, isx ? series.x : series.y)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
|
||||
write(io, readall("/tmp/dfskjdhfkh.png"))
|
||||
end
|
||||
|
||||
# function Base.show(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
|
||||
# for plt in subplt.plts
|
||||
# Qwt.refresh(plt.o)
|
||||
# end
|
||||
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
|
||||
# write(io, readall("/tmp/dfskjdhfkh.png"))
|
||||
# end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.showwidget(plt.o)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
|
||||
# for plt in subplt.plts
|
||||
# Qwt.refresh(plt.o)
|
||||
# end
|
||||
# Qwt.showwidget(subplt.o)
|
||||
# end
|
||||
@@ -1,272 +0,0 @@
|
||||
|
||||
# https://github.com/nolta/Winston.jl
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
supported_attrs(::WinstonBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:linecolor,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:bins,
|
||||
:title,
|
||||
:window_title,
|
||||
:guide, :lims, :scale,
|
||||
])
|
||||
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
|
||||
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::WinstonBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::WinstonBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _initialize_backend(::WinstonBackend; kw...)
|
||||
@eval begin
|
||||
# ENV["WINSTON_OUTPUT"] = "gtk"
|
||||
warn("Winston is no longer supported... many features will likely be broken.")
|
||||
import Winston, Gtk
|
||||
export Winston, Gtk
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
## dictionaries for conversion of Plots.jl names to Winston ones.
|
||||
const winston_linestyle = KW(:solid=>"solid",
|
||||
:dash=>"dash",
|
||||
:dot=>"dotted",
|
||||
:dashdot=>"dotdashed"
|
||||
)
|
||||
|
||||
const winston_marker = KW(:none=>".",
|
||||
:rect => "square",
|
||||
:circle=>"circle",
|
||||
:diamond=>"diamond",
|
||||
:utriangle=>"triangle",
|
||||
:dtriangle=>"down-triangle",
|
||||
:cross => "plus",
|
||||
:xcross => "cross",
|
||||
:star5 => "asterisk"
|
||||
)
|
||||
|
||||
function _before_update(plt::Plot{WinstonBackend})
|
||||
Winston.ghf(plt.o)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_backend_figure(plt::Plot{WinstonBackend})
|
||||
Winston.FramedPlot(
|
||||
title = plt.attr[:title],
|
||||
xlabel = plt.attr[:xguide],
|
||||
ylabel = plt.attr[:yguide]
|
||||
)
|
||||
end
|
||||
|
||||
copy_remove(d::KW, s::Symbol) = delete!(copy(d), s)
|
||||
|
||||
function addRegressionLineWinston(d::KW, wplt)
|
||||
xs, ys = regressionXY(d[:x], d[:y])
|
||||
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
|
||||
end
|
||||
|
||||
function getWinstonItems(plt::Plot)
|
||||
if isa(plt.o, Winston.FramedPlot)
|
||||
wplt = plt.o
|
||||
window, canvas = nothing, nothing
|
||||
else
|
||||
window, canvas, wplt = plt.o
|
||||
end
|
||||
window, canvas, wplt
|
||||
end
|
||||
|
||||
function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
||||
d = series.d
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
# until we call it normally, do the hack
|
||||
if d[:seriestype] == :bar
|
||||
d = barHack(;d...)
|
||||
end
|
||||
|
||||
|
||||
e = KW()
|
||||
e[:color] = getColor(d[:linecolor])
|
||||
e[:linewidth] = d[:linewidth]
|
||||
e[:kind] = winston_linestyle[d[:linestyle]]
|
||||
e[:symbolkind] = winston_marker[d[:markershape]]
|
||||
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
|
||||
e[:symbolsize] = d[:markersize] / 5
|
||||
|
||||
# pos # (Int,Int), move the enclosing window to this position
|
||||
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
||||
|
||||
|
||||
|
||||
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
|
||||
if d[:seriestype] == :none
|
||||
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
|
||||
|
||||
elseif d[:seriestype] == :path
|
||||
x, y = d[:x], d[:y]
|
||||
Winston.add(wplt, Winston.Curve(x, y; e...))
|
||||
|
||||
fillrange = d[:fillrange]
|
||||
if fillrange != nothing
|
||||
if isa(fillrange, AbstractVector)
|
||||
y2 = fillrange
|
||||
else
|
||||
y2 = Float64[fillrange for yi in y]
|
||||
end
|
||||
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(d[:fillcolor])))
|
||||
end
|
||||
|
||||
elseif d[:seriestype] == :scatter
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# elseif d[:seriestype] == :step
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif d[:seriestype] == :stepinverted
|
||||
# fn = Winston.XXX
|
||||
|
||||
elseif d[:seriestype] == :sticks
|
||||
Winston.add(wplt, Winston.Stems(d[:x], d[:y]; e...))
|
||||
|
||||
# elseif d[:seriestype] == :dots
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif d[:seriestype] == :histogram2d
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif d[:seriestype] == :hexbin
|
||||
# fn = Winston.XXX
|
||||
|
||||
elseif d[:seriestype] == :histogram
|
||||
hst = hist(d[:y], d[:bins])
|
||||
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
|
||||
|
||||
# elseif d[:seriestype] == :bar
|
||||
# # fn = Winston.XXX
|
||||
|
||||
else
|
||||
error("seriestype $(d[:seriestype]) not supported by Winston.")
|
||||
|
||||
end
|
||||
|
||||
|
||||
# markershape
|
||||
if d[:markershape] != :none
|
||||
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
|
||||
end
|
||||
|
||||
|
||||
# optionally add a regression line
|
||||
d[:smooth] && d[:seriestype] != :histogram && addRegressionLineWinston(d, wplt)
|
||||
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _winstonNames = KW(
|
||||
:xlims => :xrange,
|
||||
:ylims => :yrange,
|
||||
:xscale => :xlog,
|
||||
:yscale => :ylog,
|
||||
)
|
||||
|
||||
function _update_plot_object(plt::Plot{WinstonBackend}, d::KW)
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
for k in (:xguide, :yguide, :title, :xlims, :ylims)
|
||||
if haskey(d, k)
|
||||
Winston.setattr(wplt, string(get(_winstonNames, k, k)), d[k])
|
||||
end
|
||||
end
|
||||
|
||||
for k in (:xscale, :yscale)
|
||||
if haskey(d, k)
|
||||
islogscale = d[k] == :log10
|
||||
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::AbstractString)
|
||||
Winston.text(x, y, val)
|
||||
end
|
||||
|
||||
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
createWinstonAnnotationObject(plt, ann...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
|
||||
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function addWinstonLegend(plt::Plot, wplt)
|
||||
if plt.attr[:legend] != :none
|
||||
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
|
||||
end
|
||||
end
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
addWinstonLegend(plt, wplt)
|
||||
show(io, "image/png", wplt)
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
|
||||
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
if window == nothing
|
||||
if Winston.output_surface != :gtk
|
||||
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
|
||||
end
|
||||
# initialize window
|
||||
w,h = plt.attr[:size]
|
||||
canvas = Gtk.GtkCanvasLeaf()
|
||||
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
|
||||
plt.o = (window, canvas, wplt)
|
||||
end
|
||||
|
||||
addWinstonLegend(plt, wplt)
|
||||
|
||||
Winston.display(canvas, wplt)
|
||||
Gtk.showall(window)
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
|
||||
# # TODO: display/show the Subplot object
|
||||
# end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,415 +0,0 @@
|
||||
|
||||
abstract type ColorScheme end
|
||||
|
||||
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
|
||||
|
||||
export
|
||||
cgrad
|
||||
|
||||
cgrad() = default_gradient()
|
||||
|
||||
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
|
||||
colors = ColorGradient(arg, alpha=alpha).colors
|
||||
values = if values != nothing
|
||||
values
|
||||
elseif scale in (:log, :log10)
|
||||
log10(linspace(1,10,30))
|
||||
elseif scale == :log2
|
||||
log2(linspace(1,2,30))
|
||||
elseif scale == :ln
|
||||
log(linspace(1,pi,30))
|
||||
elseif scale in (:exp, :exp10)
|
||||
(exp10(linspace(0,1,30)) - 1) / 9
|
||||
else
|
||||
linspace(0, 1, length(colors))
|
||||
end
|
||||
ColorGradient(colors, values)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
getColor(scheme::ColorScheme) = getColor(scheme, 1)
|
||||
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
|
||||
|
||||
colorscheme(scheme::ColorScheme) = scheme
|
||||
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
|
||||
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
|
||||
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
|
||||
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
|
||||
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
|
||||
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
|
||||
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
|
||||
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
|
||||
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
|
||||
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
|
||||
convertColor(c::AbstractString) = parse(Colorant, c)
|
||||
convertColor(c::Symbol) = parse(Colorant, string(c))
|
||||
convertColor(c::Colorant) = c
|
||||
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
|
||||
convertColor(c::ColorScheme) = c
|
||||
convertColor(v::Void) = RGBA(0,0,0,0)
|
||||
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
|
||||
|
||||
function convertColor(c, α::Real)
|
||||
c = convertColor(c)
|
||||
RGBA(RGB(getColor(c)), α)
|
||||
end
|
||||
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
|
||||
convertColor(c, α::Void) = convertColor(c)
|
||||
|
||||
# backup... try to convert
|
||||
getColor(c) = convertColor(c)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
function darken(c, v=0.1)
|
||||
rgba = convert(RGBA, c)
|
||||
r = max(0, min(rgba.r - v, 1))
|
||||
g = max(0, min(rgba.g - v, 1))
|
||||
b = max(0, min(rgba.b - v, 1))
|
||||
RGBA(r,g,b,rgba.alpha)
|
||||
end
|
||||
function lighten(c, v=0.3)
|
||||
darken(c, -v)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
|
||||
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
|
||||
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
|
||||
|
||||
const _gradients = KW(
|
||||
:blues => [colorant"lightblue", colorant"darkblue"],
|
||||
:reds => [colorant"lightpink", colorant"darkred"],
|
||||
:greens => [colorant"lightgreen", colorant"darkgreen"],
|
||||
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
|
||||
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
|
||||
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
|
||||
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
|
||||
:rainbow => _rainbowColors,
|
||||
:lightrainbow => map(lighten, _rainbowColors),
|
||||
:darkrainbow => map(darken, _rainbowColors),
|
||||
:darktest => _testColors,
|
||||
:lighttest => map(c -> lighten(c, 0.3), _testColors),
|
||||
)
|
||||
|
||||
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
|
||||
_gradients[name] = colors
|
||||
end
|
||||
|
||||
include("color_gradients.jl")
|
||||
|
||||
default_gradient() = ColorGradient(:inferno)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
|
||||
struct ColorGradient <: ColorScheme
|
||||
colors::Vector
|
||||
values::Vector
|
||||
|
||||
function ColorGradient(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing) where S<:Real
|
||||
if length(cs) == length(vals)
|
||||
return new(convertColor(cs,alpha), collect(vals))
|
||||
end
|
||||
|
||||
# # otherwise interpolate evenly between the minval and maxval
|
||||
# minval, maxval = minimum(vals), maximum(vals)
|
||||
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
|
||||
# new(convertColor(cs,alpha), vs)
|
||||
|
||||
# interpolate the colors for each value
|
||||
vals = merge(linspace(0, 1, length(cs)), vals)
|
||||
grad = ColorGradient(cs)
|
||||
cs = [getColorZ(grad, z) for z in linspace(0, 1, length(vals))]
|
||||
new(convertColor(cs, alpha), vals)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
|
||||
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
|
||||
|
||||
|
||||
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
|
||||
function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
|
||||
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
|
||||
cs = _gradients[s]
|
||||
if vals == 0:0
|
||||
vals = linspace(0, 1, length(cs))
|
||||
end
|
||||
ColorGradient(cs, vals; kw...)
|
||||
end
|
||||
|
||||
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
|
||||
# ColorGradient(map(convertColor, cs), vals; kw...)
|
||||
# end
|
||||
|
||||
function ColorGradient(grad::ColorGradient; alpha = nothing)
|
||||
ColorGradient(convertColor(grad.colors, alpha), grad.values)
|
||||
end
|
||||
|
||||
# anything else just gets the default gradient
|
||||
function ColorGradient(cw; alpha=nothing)
|
||||
ColorGradient(default_gradient(), alpha=alpha)
|
||||
end
|
||||
|
||||
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
|
||||
|
||||
function getColorZ(gradient::ColorGradient, z::Real)
|
||||
cs = gradient.colors
|
||||
vs = gradient.values
|
||||
n = length(cs)
|
||||
@assert n > 0 && n == length(vs)
|
||||
|
||||
# can we just return the first color?
|
||||
if z <= vs[1] || n == 1
|
||||
return cs[1]
|
||||
end
|
||||
|
||||
# find the bounding colors and interpolate
|
||||
for i in 2:n
|
||||
if z <= vs[i]
|
||||
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
|
||||
end
|
||||
end
|
||||
|
||||
# if we get here, return the last color
|
||||
cs[end]
|
||||
end
|
||||
|
||||
getColorVector(gradient::ColorGradient) = gradient.colors
|
||||
|
||||
# for 0.3
|
||||
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
|
||||
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
|
||||
|
||||
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
|
||||
rgb1 = RGBA(c1)
|
||||
rgb2 = RGBA(c2)
|
||||
r = interpolate(rgb1.r, rgb2.r, w)
|
||||
g = interpolate(rgb1.g, rgb2.g, w)
|
||||
b = interpolate(rgb1.b, rgb2.b, w)
|
||||
a = interpolate(rgb1.alpha, rgb2.alpha, w)
|
||||
RGBA(r, g, b, a)
|
||||
end
|
||||
|
||||
|
||||
function interpolate(v1::Real, v2::Real, w::Real)
|
||||
(1-w) * v1 + w * v2
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a function, taking an index and returning a Colorant"
|
||||
struct ColorFunction <: ColorScheme
|
||||
f::Function
|
||||
end
|
||||
|
||||
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a function, taking an z-value and returning a Colorant"
|
||||
struct ColorZFunction <: ColorScheme
|
||||
f::Function
|
||||
end
|
||||
|
||||
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
|
||||
struct ColorVector <: ColorScheme
|
||||
v::Vector{Colorant}
|
||||
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
|
||||
end
|
||||
|
||||
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
|
||||
getColorVector(scheme::ColorVector) = scheme.v
|
||||
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a single color"
|
||||
struct ColorWrapper <: ColorScheme
|
||||
c::RGBA
|
||||
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
|
||||
end
|
||||
|
||||
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
|
||||
|
||||
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
|
||||
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
|
||||
convertColor(c::ColorWrapper, α::Void) = c.c
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
|
||||
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
|
||||
|
||||
# move closer to lighter/darker depending on background value
|
||||
function adjustAway(val, bgval, vmin=0., vmax=100.)
|
||||
if bgval < 0.5 * (vmax+vmin)
|
||||
tmp = max(val, bgval)
|
||||
return 0.5 * (tmp + max(tmp, vmax))
|
||||
else
|
||||
tmp = min(val, bgval)
|
||||
return 0.5 * (tmp + min(tmp, vmin))
|
||||
end
|
||||
end
|
||||
|
||||
# borrowed from http://stackoverflow.com/a/1855903:
|
||||
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
|
||||
|
||||
isdark(c::Colorant) = lightnessLevel(c) < 0.5
|
||||
islight(c::Colorant) = !isdark(c)
|
||||
|
||||
function convertHexToRGB(h::Unsigned)
|
||||
mask = 0x0000FF
|
||||
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
|
||||
end
|
||||
|
||||
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
|
||||
const _masterColorList = [
|
||||
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
|
||||
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
|
||||
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
|
||||
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
|
||||
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
|
||||
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
|
||||
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
|
||||
]
|
||||
const _allColors = map(convertHexToRGB, _masterColorList)
|
||||
const _darkColors = filter(isdark, _allColors)
|
||||
const _lightColors = filter(islight, _allColors)
|
||||
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
|
||||
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
|
||||
|
||||
const _defaultNumColors = 17
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
# Methods to automatically generate gradients for color selection based on
|
||||
# background color and a short list of seed colors
|
||||
|
||||
# here are some magic constants that could be changed if you really want
|
||||
const _lightness_darkbg = [80.0]
|
||||
const _lightness_lightbg = [60.0]
|
||||
const _lch_c_const = [60]
|
||||
|
||||
function adjust_lch(color, l, c)
|
||||
lch = convert(LCHab, color)
|
||||
convert(RGB, LCHab(l, c, lch.h))
|
||||
end
|
||||
|
||||
function lightness_from_background(bgcolor)
|
||||
bglight = convert(LCHab, bgcolor).l
|
||||
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
|
||||
end
|
||||
|
||||
function gradient_from_list(cs)
|
||||
zvalues = Plots.get_zvalues(length(cs))
|
||||
indices = sortperm(zvalues)
|
||||
sorted_colors = map(RGBA, cs[indices])
|
||||
sorted_zvalues = zvalues[indices]
|
||||
ColorGradient(sorted_colors, sorted_zvalues)
|
||||
end
|
||||
|
||||
function generate_colorgradient(bgcolor = colorant"white";
|
||||
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
|
||||
lightness = lightness_from_background(bgcolor),
|
||||
chroma = _lch_c_const[1],
|
||||
n = _defaultNumColors)
|
||||
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
|
||||
colors = distinguishable_colors(n,
|
||||
seed_colors,
|
||||
lchoices=Float64[lightness],
|
||||
cchoices=Float64[chroma],
|
||||
hchoices=linspace(0, 340, 20)
|
||||
)[2:end]
|
||||
gradient_from_list(colors)
|
||||
end
|
||||
|
||||
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
|
||||
grad = if palette == :auto
|
||||
generate_colorgradient(bgcolor)
|
||||
else
|
||||
ColorGradient(palette)
|
||||
end
|
||||
zrng = get_zvalues(numcolors)
|
||||
RGBA[getColorZ(grad, z) for z in zrng]
|
||||
end
|
||||
|
||||
function get_color_palette(palette::Vector{C},
|
||||
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
|
||||
palette
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function getpctrange(n::Int)
|
||||
n > 0 || error()
|
||||
n == 1 && return zeros(1)
|
||||
zs = [0.0, 1.0]
|
||||
for i in 3:n
|
||||
sorted = sort(zs)
|
||||
diffs = diff(sorted)
|
||||
widestj = 0
|
||||
widest = 0.0
|
||||
for (j,d) in enumerate(diffs)
|
||||
if d > widest
|
||||
widest = d
|
||||
widestj = j
|
||||
end
|
||||
end
|
||||
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
|
||||
end
|
||||
zs
|
||||
end
|
||||
|
||||
function get_zvalues(n::Int)
|
||||
offsets = getpctrange(ceil(Int,n/4)+1)/4
|
||||
offsets = vcat(offsets[1], offsets[3:end])
|
||||
zvalues = Float64[]
|
||||
for offset in offsets
|
||||
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
|
||||
end
|
||||
vcat(zvalues[1], 1.0, zvalues[2:n-1])
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
make255(x) = round(Int, 255 * x)
|
||||
|
||||
function webcolor(c::Color)
|
||||
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
|
||||
end
|
||||
function webcolor(c::TransparentColor)
|
||||
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
|
||||
end
|
||||
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
|
||||
webcolor(c) = webcolor(convertColor(c))
|
||||
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
|
||||
function getSeriesRGBColor(c, sp::Subplot, n::Int)
|
||||
|
||||
if c == :auto
|
||||
c = autopick(sp[:color_palette], n)
|
||||
end
|
||||
|
||||
# c should now be a subtype of ColorScheme
|
||||
colorscheme(c)
|
||||
end
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
|
||||
# TODO:
|
||||
"""
|
||||
- load Contours.jl similar to DataFrames
|
||||
- method to build grid from x/y/z vectors
|
||||
- method to wrap contours creation
|
||||
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
# # ----------------------------------------------------------
|
||||
# # ----------------------------------------------------------
|
||||
|
||||
|
||||
# immutable Vertex
|
||||
# x::Float64
|
||||
# y::Float64
|
||||
# z::Float64
|
||||
# end
|
||||
|
||||
# immutable Edge
|
||||
# v::Vertex
|
||||
# u::Vertex
|
||||
# end
|
||||
|
||||
# # ----------------------------------------------------------
|
||||
|
||||
# # one rectangle's z-values and the center vertex
|
||||
# # z is ordered: topleft, topright, bottomright, bottomleft
|
||||
# immutable GridRect
|
||||
# z::Vector{Float64}
|
||||
# center::Vertex
|
||||
# data::Vector{Vertex}
|
||||
# end
|
||||
|
||||
|
||||
|
||||
# type Grid
|
||||
# xs::Vector{Float64}
|
||||
# ys::Vector{Float64}
|
||||
# rects::Matrix{GridRect}
|
||||
# end
|
||||
|
||||
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
|
||||
# vs = sort(v)
|
||||
|
||||
# end
|
||||
|
||||
# # the goal here is to create the vertical and horizontal partitions
|
||||
# # which define the grid, so that the data is somewhat evenly split
|
||||
# function bucketData(x, y, z)
|
||||
|
||||
# end
|
||||
|
||||
|
||||
# function buildGrid(x, y, z)
|
||||
# # create
|
||||
# end
|
||||
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
|
||||
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
|
||||
# Special handling for: no args, xmin/xmax, parametric, dataframes
|
||||
# Then once inputs have been converted, build the series args, map functions, etc.
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
const FuncOrFuncs = Union{Function, AVec{Function}}
|
||||
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, d::KW)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, d::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
|
||||
|
||||
|
||||
function convertToAnyVector(args...)
|
||||
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
|
||||
# result in that array being shared. push!, etc will add too many items to that array
|
||||
|
||||
compute_x(x::Void, y::Void, z) = 1:size(z,1)
|
||||
compute_x(x::Void, y, z) = 1:size(y,1)
|
||||
compute_x(x::Function, y, z) = map(x, y)
|
||||
compute_x(x, y, z) = copy(x)
|
||||
|
||||
# compute_y(x::Void, y::Function, z) = error()
|
||||
compute_y(x::Void, y::Void, z) = 1:size(z,2)
|
||||
compute_y(x, y::Function, z) = map(y, x)
|
||||
compute_y(x, y, z) = copy(y)
|
||||
|
||||
compute_z(x, y, z::Function) = map(z, x, y)
|
||||
compute_z(x, y, z::AbstractMatrix) = Surface(z)
|
||||
compute_z(x, y, z::Void) = nothing
|
||||
compute_z(x, y, z) = copy(z)
|
||||
|
||||
nobigs(v::AVec{BigFloat}) = map(Float64, v)
|
||||
nobigs(v::AVec{BigInt}) = map(Int64, v)
|
||||
nobigs(v) = v
|
||||
|
||||
@noinline function compute_xyz(x, y, z)
|
||||
x = compute_x(x,y,z)
|
||||
y = compute_y(x,y,z)
|
||||
z = compute_z(x,y,z)
|
||||
nobigs(x), nobigs(y), nobigs(z)
|
||||
end
|
||||
|
||||
# not allowed
|
||||
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
|
||||
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
+1251
-427
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
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 Gaston = "4b11ee91-296f-5714-9832-002c20994614" begin
|
||||
fn = joinpath(@__DIR__, "backends", "gaston.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
|
||||
+73
-109
@@ -4,34 +4,6 @@
|
||||
to_pixels(m::AbsoluteLength) = m.value / 0.254
|
||||
|
||||
const _cbar_width = 5mm
|
||||
|
||||
Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
|
||||
Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
|
||||
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
|
||||
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
|
||||
Base.zero(::Type{typeof(mm)}) = 0mm
|
||||
Base.one(::Type{typeof(mm)}) = 1mm
|
||||
Base.typemin(::typeof(mm)) = -Inf*mm
|
||||
Base.typemax(::typeof(mm)) = Inf*mm
|
||||
Base.convert(::Type{F}, l::AbsoluteLength) where {F<:AbstractFloat} = convert(F, l.value)
|
||||
|
||||
# TODO: these are unintuitive and may cause tricky bugs
|
||||
# Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
|
||||
# Base.:+(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (1 + m1.value))
|
||||
# Base.:-(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 - m2.value))
|
||||
# Base.:-(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (m1.value - 1))
|
||||
|
||||
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)
|
||||
|
||||
|
||||
Base.zero(::Type{typeof(pct)}) = 0pct
|
||||
Base.one(::Type{typeof(pct)}) = 1pct
|
||||
Base.typemin(::typeof(pct)) = 0pct
|
||||
Base.typemax(::typeof(pct)) = 1pct
|
||||
|
||||
const defaultbox = BoundingBox(0mm, 0mm, 0mm, 0mm)
|
||||
|
||||
left(bbox::BoundingBox) = bbox.x0[1]
|
||||
@@ -107,11 +79,10 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
|
||||
if mix.len != 0mm
|
||||
f = (letter == :x ? width : height)
|
||||
totlen = f(plotarea(sp))
|
||||
@show totlen
|
||||
pct += mix.len / totlen
|
||||
end
|
||||
if pct != 0
|
||||
amin, amax = axis_limits(sp[Symbol(letter,:axis)])
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
xy += pct * (amax-amin)
|
||||
end
|
||||
xy
|
||||
@@ -147,7 +118,7 @@ function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
|
||||
elseif oarg in (:top, :bottom, :vcenter)
|
||||
origver = oarg
|
||||
else
|
||||
warn("Unused origin arg in bbox construction: $oarg")
|
||||
@warn("Unused origin arg in bbox construction: $oarg")
|
||||
end
|
||||
end
|
||||
bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver)
|
||||
@@ -218,6 +189,7 @@ bottompad(layout::AbstractLayout) = 0mm
|
||||
# this is the parent of the top-level layout
|
||||
struct RootLayout <: AbstractLayout end
|
||||
|
||||
Base.show(io::IO, layout::RootLayout) = Base.show_default(io, layout)
|
||||
Base.parent(::RootLayout) = nothing
|
||||
parent_bbox(::RootLayout) = defaultbox
|
||||
bbox(::RootLayout) = defaultbox
|
||||
@@ -258,7 +230,7 @@ end
|
||||
grid(args...; kw...)
|
||||
|
||||
Create a grid layout for subplots. `args` specify the dimensions, e.g.
|
||||
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two
|
||||
`grid(3,2, widths = (0.6,0.4))` creates a grid with three rows and two
|
||||
columns of different width.
|
||||
"""
|
||||
grid(args...; kw...) = GridLayout(args...; kw...)
|
||||
@@ -268,7 +240,7 @@ function GridLayout(dims...;
|
||||
widths = zeros(dims[2]),
|
||||
heights = zeros(dims[1]),
|
||||
kw...)
|
||||
grid = Matrix{AbstractLayout}(dims...)
|
||||
grid = Matrix{AbstractLayout}(undef, dims...)
|
||||
layout = GridLayout(
|
||||
parent,
|
||||
(20mm, 5mm, 2mm, 10mm),
|
||||
@@ -345,10 +317,8 @@ end
|
||||
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
|
||||
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm])
|
||||
nr, nc = size(layout)
|
||||
|
||||
# # create a matrix for each minimum padding direction
|
||||
# _update_min_padding!(layout)
|
||||
|
||||
minpad_left = map(leftpad, layout.grid)
|
||||
minpad_top = map(toppad, layout.grid)
|
||||
minpad_right = map(rightpad, layout.grid)
|
||||
@@ -357,10 +327,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
||||
# get the max horizontal (left and right) padding over columns,
|
||||
# and max vertical (bottom and top) padding over rows
|
||||
# TODO: add extra padding here
|
||||
pad_left = maximum(minpad_left, 1)
|
||||
pad_top = maximum(minpad_top, 2)
|
||||
pad_right = maximum(minpad_right, 1)
|
||||
pad_bottom = maximum(minpad_bottom, 2)
|
||||
pad_left = maximum(minpad_left, dims = 1)
|
||||
pad_top = maximum(minpad_top, dims = 2)
|
||||
pad_right = maximum(minpad_right, dims = 1)
|
||||
pad_bottom = maximum(minpad_bottom, dims = 2)
|
||||
|
||||
# make sure the perimeter match the parent
|
||||
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
|
||||
@@ -407,10 +377,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
||||
# this is the minimum perimeter as decided by this child's parent, so that
|
||||
# all children on this border have the same value
|
||||
min_child_perimeter = [
|
||||
c == 1 ? layout.minpad[1] : 0mm,
|
||||
r == 1 ? layout.minpad[2] : 0mm,
|
||||
c == nc ? layout.minpad[3] : 0mm,
|
||||
r == nr ? layout.minpad[4] : 0mm
|
||||
c == 1 ? layout.minpad[1] : pad_left[c],
|
||||
r == 1 ? layout.minpad[2] : pad_top[r],
|
||||
c == nc ? layout.minpad[3] : pad_right[c],
|
||||
r == nr ? layout.minpad[4] : pad_bottom[r]
|
||||
]
|
||||
|
||||
# recursively update the child's children
|
||||
@@ -436,7 +406,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
calc_num_subplots(layout::AbstractLayout) = 1
|
||||
calc_num_subplots(layout::AbstractLayout) = get(layout.attr, :blank, false) ? 0 : 1
|
||||
function calc_num_subplots(layout::GridLayout)
|
||||
tot = 0
|
||||
for l in layout.grid
|
||||
@@ -464,12 +434,12 @@ end
|
||||
# constructors
|
||||
|
||||
# pass the layout arg through
|
||||
function layout_args(d::KW)
|
||||
layout_args(get(d, :layout, default(:layout)))
|
||||
function layout_args(plotattributes::AKW)
|
||||
layout_args(plotattributes[:layout])
|
||||
end
|
||||
|
||||
function layout_args(d::KW, n_override::Integer)
|
||||
layout, n = layout_args(get(d, :layout, n_override))
|
||||
function layout_args(plotattributes::AKW, n_override::Integer)
|
||||
layout, n = layout_args(n_override, get(plotattributes, :layout, n_override))
|
||||
if n != n_override
|
||||
error("When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.")
|
||||
end
|
||||
@@ -481,12 +451,27 @@ function layout_args(n::Integer)
|
||||
GridLayout(nr, nc), n
|
||||
end
|
||||
|
||||
function layout_args(sztup::NTuple{2,I}) where I<:Integer
|
||||
function layout_args(sztup::NTuple{2, Integer})
|
||||
nr, nc = sztup
|
||||
GridLayout(nr, nc), nr*nc
|
||||
end
|
||||
|
||||
function layout_args(sztup::NTuple{3,I}) where I<:Integer
|
||||
layout_args(n_override::Integer, n::Integer) = layout_args(n)
|
||||
layout_args(n, sztup::NTuple{2, Integer}) = layout_args(sztup)
|
||||
|
||||
function layout_args(n, sztup::Tuple{Colon, Integer})
|
||||
nc = sztup[2]
|
||||
nr = ceil(Int, n / nc)
|
||||
GridLayout(nr, nc), n
|
||||
end
|
||||
|
||||
function layout_args(n, sztup::Tuple{Integer, Colon})
|
||||
nr = sztup[1]
|
||||
nc = ceil(Int, n / nr)
|
||||
GridLayout(nr, nc), n
|
||||
end
|
||||
|
||||
function layout_args(sztup::NTuple{3, Integer})
|
||||
n, nr, nc = sztup
|
||||
nr, nc = compute_gridsize(n, nr, nc)
|
||||
GridLayout(nr, nc), n
|
||||
@@ -499,6 +484,8 @@ function layout_args(layout::GridLayout)
|
||||
layout, n
|
||||
end
|
||||
|
||||
layout_args(n_override::Integer, layout::GridLayout) = layout_args(layout)
|
||||
|
||||
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
|
||||
|
||||
|
||||
@@ -507,34 +494,42 @@ layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
|
||||
|
||||
function build_layout(args...)
|
||||
layout, n = layout_args(args...)
|
||||
build_layout(layout, n)
|
||||
build_layout(layout, n, Array{Plot}(undef, 0))
|
||||
end
|
||||
|
||||
# # just a single subplot
|
||||
# function build_layout(sp::Subplot, n::Integer)
|
||||
# sp, Subplot[sp], SubplotMap(gensym() => sp)
|
||||
# end
|
||||
|
||||
# n is the number of subplots... build a grid and initialize the inner subplots recursively
|
||||
function build_layout(layout::GridLayout, n::Integer)
|
||||
# n is the number of subplots...
|
||||
function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot})
|
||||
nr, nc = size(layout)
|
||||
subplots = Subplot[]
|
||||
spmap = SubplotMap()
|
||||
empty = isempty(plts)
|
||||
i = 0
|
||||
for r=1:nr, c=1:nc
|
||||
l = layout[r,c]
|
||||
for r = 1:nr, c = 1:nc
|
||||
l = layout[r, c]
|
||||
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
|
||||
sp = Subplot(backend(), parent=layout)
|
||||
layout[r,c] = sp
|
||||
push!(subplots, sp)
|
||||
spmap[attr(l,:label,gensym())] = sp
|
||||
if empty
|
||||
# initialize the inner subplots recursively
|
||||
sp = Subplot(backend(), parent=layout)
|
||||
layout[r, c] = sp
|
||||
push!(subplots, sp)
|
||||
spmap[attr(l,:label,gensym())] = sp
|
||||
inc = 1
|
||||
else
|
||||
# build a layout from a list of existing Plot objects
|
||||
plt = popfirst!(plts) # grab the first plot out of the list
|
||||
layout[r, c] = plt.layout
|
||||
append!(subplots, plt.subplots)
|
||||
merge!(spmap, plt.spmap)
|
||||
inc = length(plt.subplots)
|
||||
end
|
||||
if get(l.attr, :width, :auto) != :auto
|
||||
layout.widths[c] = attr(l,:width)
|
||||
end
|
||||
if get(l.attr, :height, :auto) != :auto
|
||||
layout.heights[r] = attr(l,:height)
|
||||
end
|
||||
i += 1
|
||||
i += inc
|
||||
elseif isa(l, GridLayout)
|
||||
# sub-grid
|
||||
if get(l.attr, :width, :auto) != :auto
|
||||
@@ -543,11 +538,11 @@ function build_layout(layout::GridLayout, n::Integer)
|
||||
if get(l.attr, :height, :auto) != :auto
|
||||
layout.heights[r] = attr(l,:height)
|
||||
end
|
||||
l, sps, m = build_layout(l, n-i)
|
||||
l, sps, m = build_layout(l, n - i, plts)
|
||||
append!(subplots, sps)
|
||||
merge!(spmap, m)
|
||||
i += length(sps)
|
||||
elseif isa(l, Subplot)
|
||||
elseif isa(l, Subplot) && empty
|
||||
error("Subplot exists. Cannot re-use existing layout. Please make a new one.")
|
||||
end
|
||||
i >= n && break # only add n subplots
|
||||
@@ -556,50 +551,11 @@ function build_layout(layout::GridLayout, n::Integer)
|
||||
layout, subplots, spmap
|
||||
end
|
||||
|
||||
# build a layout from a list of existing Plot objects
|
||||
# TODO... much of the logic overlaps with the method above... can we merge?
|
||||
function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
|
||||
nr, nc = size(layout)
|
||||
subplots = Subplot[]
|
||||
spmap = SubplotMap()
|
||||
i = 0
|
||||
for r=1:nr, c=1:nc
|
||||
l = layout[r,c]
|
||||
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
|
||||
plt = shift!(plts) # grab the first plot out of the list
|
||||
layout[r,c] = plt.layout
|
||||
append!(subplots, plt.subplots)
|
||||
merge!(spmap, plt.spmap)
|
||||
if get(l.attr, :width, :auto) != :auto
|
||||
layout.widths[c] = attr(l,:width)
|
||||
end
|
||||
if get(l.attr, :height, :auto) != :auto
|
||||
layout.heights[r] = attr(l,:height)
|
||||
end
|
||||
i += length(plt.subplots)
|
||||
elseif isa(l, GridLayout)
|
||||
# sub-grid
|
||||
if get(l.attr, :width, :auto) != :auto
|
||||
layout.widths[c] = attr(l,:width)
|
||||
end
|
||||
if get(l.attr, :height, :auto) != :auto
|
||||
layout.heights[r] = attr(l,:height)
|
||||
end
|
||||
l, sps, m = build_layout(l, numsp-i, plts)
|
||||
append!(subplots, sps)
|
||||
merge!(spmap, m)
|
||||
i += length(sps)
|
||||
end
|
||||
i >= numsp && break # only add n subplots
|
||||
end
|
||||
layout, subplots, spmap
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# @layout macro
|
||||
|
||||
function add_layout_pct!(kw::KW, v::Expr, idx::Integer, nidx::Integer)
|
||||
function add_layout_pct!(kw::AKW, v::Expr, idx::Integer, nidx::Integer)
|
||||
# dump(v)
|
||||
# something like {0.2w}?
|
||||
if v.head == :call && v.args[1] == :*
|
||||
@@ -620,7 +576,7 @@ function add_layout_pct!(kw::KW, v::Expr, idx::Integer, nidx::Integer)
|
||||
error("Couldn't match layout curly (idx=$idx): $v")
|
||||
end
|
||||
|
||||
function add_layout_pct!(kw::KW, v::Number, idx::Integer)
|
||||
function add_layout_pct!(kw::AKW, v::Number, idx::Integer)
|
||||
# kw[idx == 1 ? :w : :h] = v*pct
|
||||
idx == 1 && (kw[:w] = v*pct)
|
||||
(idx == 2 || nidx == 1) && (kw[:h] = v*pct)
|
||||
@@ -788,9 +744,17 @@ end
|
||||
|
||||
"Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis."
|
||||
function twinx(sp::Subplot)
|
||||
sp[:right_margin] = max(sp[:right_margin], 30px)
|
||||
plot!(sp.plt, inset = (sp[:subplot_index], bbox(0,0,1,1)))
|
||||
plot!(sp.plt,
|
||||
inset = (sp[:subplot_index], bbox(0,0,1,1)),
|
||||
right_margin = sp[:right_margin],
|
||||
left_margin = sp[:left_margin],
|
||||
top_margin = sp[:top_margin],
|
||||
bottom_margin = sp[:bottom_margin],
|
||||
)
|
||||
twinsp = sp.plt.subplots[end]
|
||||
twinsp[:xaxis][:grid] = false
|
||||
twinsp[:yaxis][:grid] = false
|
||||
twinsp[:xaxis][:showaxis] = false
|
||||
twinsp[:yaxis][:mirror] = true
|
||||
twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0)
|
||||
link_axes!(sp[:xaxis], twinsp[:xaxis])
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
```julia
|
||||
legend_pos_from_angle(theta, xmin, xcenter, xmax, ymin, ycenter, ymax, inout)
|
||||
```
|
||||
|
||||
Return `(x,y)` at an angle `theta` degrees from
|
||||
`(xcenter,ycenter)` on a rectangle defined by (`xmin`,
|
||||
`xmax`, `ymin`, `ymax`).
|
||||
"""
|
||||
function legend_pos_from_angle(theta, xmin, xcenter, xmax, ymin, ycenter, ymax)
|
||||
(s,c) = sincosd(theta)
|
||||
x = c < 0 ? (xmin-xcenter)/c : (xmax-xcenter)/c
|
||||
y = s < 0 ? (ymin-ycenter)/s : (ymax-ycenter)/s
|
||||
A = min(x,y)
|
||||
return (xcenter + A*c, ycenter + A*s)
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Split continuous range `[-1,1]` evenly into an integer `[1,2,3]`
|
||||
"""
|
||||
function legend_anchor_index(x)
|
||||
x<-1//3 && return 1
|
||||
x<1//3 && return 2
|
||||
return 3
|
||||
end
|
||||
|
||||
"""
|
||||
Turn legend argument into a (theta, :inner) or (theta, :outer) tuple.
|
||||
For backends where legend position is given in normal coordinates (0,0) -- (1,1),
|
||||
so :topleft exactly corresponds to (45, :inner) etc.
|
||||
|
||||
If `leg` is a (::Real,::Real) tuple, keep it as is.
|
||||
"""
|
||||
legend_angle(leg::Real) = (leg,:inner)
|
||||
legend_angle(leg::Tuple{S,T}) where {S<:Real,T<:Real} = leg
|
||||
legend_angle(leg::Tuple{S,Symbol}) where S<:Real = leg
|
||||
legend_angle(leg::Symbol) = get(
|
||||
(
|
||||
topleft = (135,:inner),
|
||||
top = (90, :inner),
|
||||
topright = (45, :inner),
|
||||
left = (180,:inner),
|
||||
right = (0, :inner),
|
||||
bottomleft = (225,:inner),
|
||||
bottom = (270,:inner),
|
||||
bottomright = (315,:inner),
|
||||
outertopleft = (135,:outer),
|
||||
outertop = (90, :outer),
|
||||
outertopright = (45, :outer),
|
||||
outerleft = (180,:outer),
|
||||
outerright = (0, :outer),
|
||||
outerbottomleft = (225,:outer),
|
||||
outerbottom = (270,:outer),
|
||||
outerbottomright = (315,:outer),
|
||||
),
|
||||
leg,
|
||||
(45, :inner)
|
||||
)
|
||||
+123
-211
@@ -1,100 +1,104 @@
|
||||
|
||||
|
||||
defaultOutputFormat(plt::Plot) = "png"
|
||||
|
||||
function png(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "png")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/png"), plt)
|
||||
close(io)
|
||||
fn = addExtension(fn, "png")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/png"), plt)
|
||||
close(io)
|
||||
end
|
||||
png(fn::AbstractString) = png(current(), fn)
|
||||
|
||||
function svg(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "svg")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/svg+xml"), plt)
|
||||
close(io)
|
||||
fn = addExtension(fn, "svg")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/svg+xml"), plt)
|
||||
close(io)
|
||||
end
|
||||
svg(fn::AbstractString) = svg(current(), fn)
|
||||
|
||||
|
||||
function pdf(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "pdf")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/pdf"), plt)
|
||||
close(io)
|
||||
fn = addExtension(fn, "pdf")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/pdf"), plt)
|
||||
close(io)
|
||||
end
|
||||
pdf(fn::AbstractString) = pdf(current(), fn)
|
||||
|
||||
|
||||
function ps(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "ps")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/postscript"), plt)
|
||||
close(io)
|
||||
fn = addExtension(fn, "ps")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/postscript"), plt)
|
||||
close(io)
|
||||
end
|
||||
ps(fn::AbstractString) = ps(current(), fn)
|
||||
|
||||
function eps(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "eps")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/eps"), plt)
|
||||
close(io)
|
||||
fn = addExtension(fn, "eps")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/eps"), plt)
|
||||
close(io)
|
||||
end
|
||||
eps(fn::AbstractString) = eps(current(), fn)
|
||||
|
||||
function tex(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "tex")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/x-tex"), plt)
|
||||
close(io)
|
||||
fn = addExtension(fn, "tex")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/x-tex"), plt)
|
||||
close(io)
|
||||
end
|
||||
tex(fn::AbstractString) = tex(current(), fn)
|
||||
|
||||
function json(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "json")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/vnd.plotly.v1+json"), plt)
|
||||
close(io)
|
||||
end
|
||||
json(fn::AbstractString) = json(current(), fn)
|
||||
|
||||
function html(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "html")
|
||||
io = open(fn, "w")
|
||||
_use_remote[] = true
|
||||
show(io, MIME("text/html"), plt)
|
||||
_use_remote[] = false
|
||||
close(io)
|
||||
end
|
||||
html(fn::AbstractString) = html(current(), fn)
|
||||
|
||||
function txt(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "txt")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("text/plain"), plt)
|
||||
close(io)
|
||||
end
|
||||
txt(fn::AbstractString) = txt(current(), fn)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
const _savemap = Dict(
|
||||
"png" => png,
|
||||
"svg" => svg,
|
||||
"pdf" => pdf,
|
||||
"ps" => ps,
|
||||
"ps" => ps,
|
||||
"eps" => eps,
|
||||
"tex" => tex,
|
||||
"json" => json,
|
||||
"html" => html,
|
||||
)
|
||||
"tikz" => tex,
|
||||
"txt" => txt,
|
||||
)
|
||||
|
||||
function getExtension(fn::AbstractString)
|
||||
pieces = split(fn, ".")
|
||||
length(pieces) > 1 || error("Can't extract file extension: ", fn)
|
||||
ext = pieces[end]
|
||||
haskey(_savemap, ext) || error("Invalid file extension: ", fn)
|
||||
ext
|
||||
end
|
||||
const _extension_map = Dict("tikz" => "tex")
|
||||
|
||||
function addExtension(fn::AbstractString, ext::AbstractString)
|
||||
try
|
||||
oldext = getExtension(fn)
|
||||
if oldext == ext
|
||||
return fn
|
||||
oldfn, oldext = splitext(fn)
|
||||
oldext = chop(oldext, head = 1, tail = 0)
|
||||
if get(_extension_map, oldext, oldext) == ext
|
||||
return fn
|
||||
else
|
||||
return "$fn.$ext"
|
||||
return string(fn, ".", ext)
|
||||
end
|
||||
catch
|
||||
return "$fn.$ext"
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -105,27 +109,28 @@ type is inferred from the file extension. All backends support png and pdf
|
||||
file types, some also support svg, ps, eps, html and tex.
|
||||
"""
|
||||
function savefig(plt::Plot, fn::AbstractString)
|
||||
fn = abspath(expanduser(fn))
|
||||
|
||||
# get the extension
|
||||
local ext
|
||||
try
|
||||
ext = getExtension(fn)
|
||||
catch
|
||||
# if we couldn't extract the extension, add the default
|
||||
ext = defaultOutputFormat(plt)
|
||||
fn = addExtension(fn, ext)
|
||||
end
|
||||
# get the extension
|
||||
_, ext = splitext(fn)
|
||||
ext = chop(ext, head = 1, tail = 0)
|
||||
if isempty(ext)
|
||||
ext = defaultOutputFormat(plt)
|
||||
end
|
||||
|
||||
# save it
|
||||
func = get(_savemap, ext) do
|
||||
error("Unsupported extension $ext with filename ", fn)
|
||||
end
|
||||
func(plt, fn)
|
||||
# save it
|
||||
if haskey(_savemap, ext)
|
||||
func = _savemap[ext]
|
||||
return func(plt, fn)
|
||||
else
|
||||
error("Invalid file extension: ", fn)
|
||||
end
|
||||
end
|
||||
savefig(fn::AbstractString) = savefig(current(), fn)
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
"""
|
||||
gui([plot])
|
||||
|
||||
@@ -145,25 +150,16 @@ function Base.display(::PlotsDisplay, plt::Plot)
|
||||
_display(plt)
|
||||
end
|
||||
|
||||
# override the REPL display to open a gui window
|
||||
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
|
||||
|
||||
|
||||
_do_plot_show(plt, showval::Bool) = showval && gui(plt)
|
||||
function _do_plot_show(plt, showval::Symbol)
|
||||
showval == :gui && gui(plt)
|
||||
showval in (:inline,:ijulia) && inline(plt)
|
||||
showval in (:inline, :ijulia) && inline(plt)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
const _best_html_output_type = KW(
|
||||
:pyplot => :png,
|
||||
:unicodeplots => :txt,
|
||||
:glvisualize => :png,
|
||||
:plotlyjs => :html,
|
||||
:plotly => :html
|
||||
)
|
||||
const _best_html_output_type =
|
||||
KW(:pyplot => :png, :unicodeplots => :txt, :plotlyjs => :html, :plotly => :html)
|
||||
|
||||
# a backup for html... passes to svg or png depending on the html_output_format arg
|
||||
function _show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
@@ -172,10 +168,15 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
if output_type == :png
|
||||
# info("writing png to html output")
|
||||
print(io, "<img src=\"data:image/png;base64,", base64encode(show, MIME("image/png"), plt), "\" />")
|
||||
# @info("writing png to html output")
|
||||
print(
|
||||
io,
|
||||
"<img src=\"data:image/png;base64,",
|
||||
base64encode(show, MIME("image/png"), plt),
|
||||
"\" />",
|
||||
)
|
||||
elseif output_type == :svg
|
||||
# info("writing svg to html output")
|
||||
# @info("writing svg to html output")
|
||||
show(io, MIME("image/svg+xml"), plt)
|
||||
elseif output_type == :txt
|
||||
show(io, MIME("text/plain"), plt)
|
||||
@@ -184,56 +185,46 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
end
|
||||
end
|
||||
|
||||
# delegate mimewritable (showable on julia 0.7) to _show instead
|
||||
function Base.mimewritable(m::M, plt::P) where {M<:MIME, P<:Plot}
|
||||
return method_exists(_show, Tuple{IO, M, P})
|
||||
# delegate showable to _show instead
|
||||
function Base.showable(m::M, plt::P) where {M <: MIME, P <: Plot}
|
||||
return hasmethod(_show, Tuple{IO, M, P})
|
||||
end
|
||||
|
||||
function _display(plt::Plot)
|
||||
warn("_display is not defined for this backend.")
|
||||
@warn("_display is not defined for this backend.")
|
||||
end
|
||||
|
||||
Base.show(io::IO, m::MIME"text/plain", plt::Plot) = show(io, plt)
|
||||
# for writing to io streams... first prepare, then callback
|
||||
for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml",
|
||||
"application/eps", "application/pdf", "application/postscript",
|
||||
"application/x-tex")
|
||||
for mime in (
|
||||
"text/html",
|
||||
"image/png",
|
||||
"image/eps",
|
||||
"image/svg+xml",
|
||||
"application/eps",
|
||||
"application/pdf",
|
||||
"application/postscript",
|
||||
"application/x-tex",
|
||||
"application/vnd.plotly.v1+json",
|
||||
)
|
||||
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
if haskey(io, :juno_plotsize)
|
||||
showjuno(io, m, plt)
|
||||
else
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
end
|
||||
|
||||
# default text/plain for all backends
|
||||
_show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
|
||||
Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) =
|
||||
showjuno(io, MIME("text/html"), plt)
|
||||
|
||||
"Close all open gui windows of the current backend"
|
||||
closeall() = closeall(backend())
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
|
||||
|
||||
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
|
||||
if is_installed("FileIO")
|
||||
@eval import FileIO
|
||||
function _show(io::IO, ::MIME"image/png", plt::Plot{<:PDFBackends})
|
||||
fn = tempname()
|
||||
|
||||
# first save a pdf file
|
||||
pdf(plt, fn)
|
||||
|
||||
# load that pdf into a FileIO Stream
|
||||
s = FileIO.load(fn * ".pdf")
|
||||
|
||||
# save a png
|
||||
pngfn = fn * ".png"
|
||||
FileIO.save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, readstring(open(pngfn)))
|
||||
end
|
||||
end
|
||||
|
||||
# function html_output_format(fmt)
|
||||
# if fmt == "png"
|
||||
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
@@ -250,112 +241,33 @@ end
|
||||
#
|
||||
# html_output_format("svg")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# IJulia
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@require IJulia begin
|
||||
if IJulia.inited
|
||||
|
||||
"""
|
||||
Add extra jupyter mimetypes to display_dict based on the plot backed.
|
||||
|
||||
The default is nothing, except for plotly based backends, where it
|
||||
adds data for `application/vnd.plotly.v1+json` that is used in
|
||||
frontends like jupyterlab and nteract.
|
||||
"""
|
||||
_extra_mime_info!(plt::Plot, out::Dict) = out
|
||||
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
|
||||
out
|
||||
end
|
||||
|
||||
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
output_type = Symbol(plt.attr[:html_output_format])
|
||||
if output_type == :auto
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
out = Dict()
|
||||
if output_type == :txt
|
||||
mime = "text/plain"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :png
|
||||
mime = "image/png"
|
||||
out[mime] = base64encode(show, MIME(mime), plt)
|
||||
elseif output_type == :svg
|
||||
mime = "image/svg+xml"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :html
|
||||
mime = "text/html"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
else
|
||||
error("Unsupported output type $output_type")
|
||||
end
|
||||
_extra_mime_info!(plt, out)
|
||||
out
|
||||
end
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Atom PlotPane
|
||||
# ---------------------------------------------------------
|
||||
@require Juno begin
|
||||
import Hiccup, Media
|
||||
function showjuno(io::IO, m, plt)
|
||||
dpi = plt[:dpi]
|
||||
|
||||
if Juno.isactive()
|
||||
Media.media(Plot, Media.Plot)
|
||||
jratio = get(io, :juno_dpi_ratio, 1)
|
||||
|
||||
function Juno.render(e::Juno.Editor, plt::Plot)
|
||||
Juno.render(e, nothing)
|
||||
end
|
||||
plt[:dpi] = jratio * Plots.DPI
|
||||
|
||||
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
# temporarily overwrite size to be Atom.plotsize
|
||||
sz = plt[:size]
|
||||
dpi = plt[:dpi]
|
||||
thickness_scaling = plt[:thickness_scaling]
|
||||
jsize = Juno.plotsize()
|
||||
jsize[1] == 0 && (jsize[1] = 400)
|
||||
jsize[2] == 0 && (jsize[2] = 500)
|
||||
|
||||
scale = minimum(jsize[i] / sz[i] for i in 1:2)
|
||||
plt[:size] = (s * scale for s in sz)
|
||||
plt[:dpi] = Plots.DPI
|
||||
plt[:thickness_scaling] *= scale
|
||||
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
|
||||
plt[:size] = sz
|
||||
plt[:dpi] = dpi
|
||||
plt[:thickness_scaling] = thickness_scaling
|
||||
end
|
||||
# special handling for PlotlyJS
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
end
|
||||
else
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
s = "PlotPane turned off. Unset ENV[\"PLOTS_USE_ATOM_PLOTPANE\"] and restart Julia to enable it."
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
|
||||
# special handling for plotly... use PlotsDisplay
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
s = "PlotPane turned off. The plotly backend cannot render in the PlotPane due to javascript issues. Plotlyjs is similar to plotly and is compatible with the plot pane."
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
prepare_output(plt)
|
||||
try
|
||||
_showjuno(io, m, plt)
|
||||
finally
|
||||
plt[:dpi] = dpi
|
||||
end
|
||||
end
|
||||
|
||||
function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
|
||||
if Symbol(plt.attr[:html_output_format]) ≠ :svg
|
||||
throw(MethodError(show, (typeof(m), typeof(plt))))
|
||||
else
|
||||
_show(io, m, plt)
|
||||
end
|
||||
end
|
||||
|
||||
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot) = false
|
||||
|
||||
_showjuno(io::IO, m, plt) = _show(io, m, plt)
|
||||
|
||||
+200
-237
@@ -1,101 +1,73 @@
|
||||
# RecipesPipeline API
|
||||
|
||||
## Warnings
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# preprocessing
|
||||
|
||||
function command_idx(kw_list::AVec{KW}, kw::KW)
|
||||
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
||||
end
|
||||
|
||||
function _expand_seriestype_array(d::KW, args)
|
||||
sts = get(d, :seriestype, :path)
|
||||
if typeof(sts) <: AbstractArray
|
||||
delete!(d, :seriestype)
|
||||
RecipeData[begin
|
||||
dc = copy(d)
|
||||
dc[:seriestype] = sts[r:r,:]
|
||||
RecipeData(dc, args)
|
||||
end for r=1:size(sts,1)]
|
||||
else
|
||||
RecipeData[RecipeData(copy(d), args)]
|
||||
end
|
||||
end
|
||||
|
||||
function _preprocess_args(d::KW, args, still_to_process::Vector{RecipeData})
|
||||
# the grouping mechanism is a recipe on a GroupBy object
|
||||
# we simply add the GroupBy object to the front of the args list to allow
|
||||
# the recipe to be applied
|
||||
if haskey(d, :group)
|
||||
args = (extractGroupArgs(d[:group], args...), args...)
|
||||
end
|
||||
|
||||
# if we were passed a vector/matrix of seriestypes and there's more than one row,
|
||||
# we want to duplicate the inputs, once for each seriestype row.
|
||||
if !isempty(args)
|
||||
append!(still_to_process, _expand_seriestype_array(d, args))
|
||||
end
|
||||
|
||||
# remove subplot and axis args from d... they will be passed through in the kw_list
|
||||
if !isempty(args)
|
||||
for (k,v) in d
|
||||
for defdict in (_subplot_defaults,
|
||||
_axis_defaults,
|
||||
_axis_defaults_byletter)
|
||||
if haskey(defdict, k)
|
||||
delete!(d, k)
|
||||
function RecipesPipeline.warn_on_recipe_aliases!(
|
||||
plt::Plot,
|
||||
plotattributes::AKW,
|
||||
recipe_type::Symbol,
|
||||
@nospecialize(args)
|
||||
)
|
||||
for k in keys(plotattributes)
|
||||
if !is_default_attribute(k)
|
||||
dk = get(_keyAliases, k, k)
|
||||
if k !== dk
|
||||
if recipe_type == :user
|
||||
signature_string = RecipesPipeline.userrecipe_signature_string(args)
|
||||
elseif recipe_type == :type
|
||||
signature_string = RecipesPipeline.typerecipe_signature_string(args)
|
||||
elseif recipe_type == :plot
|
||||
signature_string = RecipesPipeline.plotrecipe_signature_string(args)
|
||||
elseif recipe_type == :series
|
||||
signature_string = RecipesPipeline.seriesrecipe_signature_string(args)
|
||||
else
|
||||
throw(ArgumentError("Invalid recipe type `$recipe_type`"))
|
||||
end
|
||||
@warn "Attribute alias `$k` detected in the $recipe_type recipe defined for the signature $signature_string. To ensure expected behavior it is recommended to use the default attribute `$dk`."
|
||||
end
|
||||
plotattributes[dk] = RecipesPipeline.pop_kw!(plotattributes, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
## Grouping
|
||||
|
||||
RecipesPipeline.splittable_attribute(plt::Plot, key, val::SeriesAnnotations, len) =
|
||||
RecipesPipeline.splittable_attribute(plt, key, val.strs, len)
|
||||
|
||||
function RecipesPipeline.split_attribute(plt::Plot, key, val::SeriesAnnotations, indices)
|
||||
split_strs = RecipesPipeline.split_attribute(plt, key, val.strs, indices)
|
||||
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor)
|
||||
end
|
||||
|
||||
|
||||
## Preprocessing attributes
|
||||
function RecipesPipeline.preprocess_axis_args!(plt::Plot, plotattributes, letter)
|
||||
# Fix letter for seriestypes that are x only but data gets passed as y
|
||||
if treats_y_as_x(get(plotattributes, :seriestype, :path))
|
||||
if get(plotattributes, :orientation, :vertical) == :vertical
|
||||
letter = :x
|
||||
end
|
||||
end
|
||||
|
||||
args
|
||||
plotattributes[:letter] = letter
|
||||
RecipesPipeline.preprocess_axis_args!(plt, plotattributes)
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# user recipes
|
||||
RecipesPipeline.preprocess_attributes!(plt::Plot, plotattributes) =
|
||||
RecipesPipeline.preprocess_attributes!(plotattributes) # in src/args.jl
|
||||
|
||||
RecipesPipeline.is_axis_attribute(plt::Plot, attr) = is_axis_attr_noletter(attr) # in src/args.jl
|
||||
|
||||
RecipesPipeline.is_subplot_attribute(plt::Plot, attr) = is_subplot_attr(attr) # in src/args.jl
|
||||
|
||||
|
||||
function _process_userrecipes(plt::Plot, d::KW, args)
|
||||
still_to_process = RecipeData[]
|
||||
args = _preprocess_args(d, args, still_to_process)
|
||||
## User recipes
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
# we are keeping a stack of series that still need to be processed.
|
||||
# each pass through the loop, we pop one off and apply the recipe.
|
||||
# the recipe will return a list a Series objects... the ones that are
|
||||
# finished (no more args) get added to the kw_list, the ones that are not
|
||||
# are placed on top of the stack and are then processed further.
|
||||
kw_list = KW[]
|
||||
while !isempty(still_to_process)
|
||||
# grab the first in line to be processed and either add it to the kw_list or
|
||||
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
|
||||
# for further processing.
|
||||
next_series = shift!(still_to_process)
|
||||
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
|
||||
if !(typeof(next_series) <: RecipeData)
|
||||
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
|
||||
end
|
||||
if isempty(next_series.args)
|
||||
_process_userrecipe(plt, kw_list, next_series)
|
||||
else
|
||||
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
||||
prepend!(still_to_process,rd_list)
|
||||
end
|
||||
end
|
||||
|
||||
# don't allow something else to handle it
|
||||
d[:smooth] = false
|
||||
kw_list
|
||||
end
|
||||
|
||||
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
|
||||
# when the arg tuple is empty, that means there's nothing left to recursively
|
||||
# process... finish up and add to the kw_list
|
||||
kw = recipedata.d
|
||||
preprocessArgs!(kw)
|
||||
function RecipesPipeline.process_userrecipe!(plt::Plot, kw_list, kw)
|
||||
_preprocess_userrecipe(kw)
|
||||
warnOnUnsupported_scales(plt.backend, kw)
|
||||
|
||||
warn_on_unsupported_scales(plt.backend, kw)
|
||||
# add the plot index
|
||||
plt.n += 1
|
||||
kw[:series_plotindex] = plt.n
|
||||
@@ -106,35 +78,34 @@ function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeD
|
||||
return
|
||||
end
|
||||
|
||||
function _preprocess_userrecipe(kw::KW)
|
||||
function _preprocess_userrecipe(kw::AKW)
|
||||
_add_markershape(kw)
|
||||
|
||||
# if there was a grouping, filter the data here
|
||||
_filter_input_data!(kw)
|
||||
|
||||
# map marker_z if it's a Function
|
||||
if isa(get(kw, :marker_z, nothing), Function)
|
||||
# TODO: should this take y and/or z as arguments?
|
||||
kw[:marker_z] = map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
|
||||
kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) :
|
||||
map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
|
||||
end
|
||||
|
||||
# map line_z if it's a Function
|
||||
if isa(get(kw, :line_z, nothing), Function)
|
||||
kw[:line_z] = map(kw[:line_z], kw[:x], kw[:y], kw[:z])
|
||||
kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) :
|
||||
map(kw[:line_z], kw[:x], kw[:y], kw[:z])
|
||||
end
|
||||
|
||||
# convert a ribbon into a fillrange
|
||||
if get(kw, :ribbon, nothing) != nothing
|
||||
if get(kw, :ribbon, nothing) !== nothing
|
||||
make_fillrange_from_ribbon(kw)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
|
||||
function _add_errorbar_kw(kw_list::Vector{KW}, kw::AKW)
|
||||
# handle error bars by creating new recipedata data... these will have
|
||||
# the same recipedata index as the recipedata they are copied from
|
||||
for esym in (:xerror, :yerror)
|
||||
if get(kw, esym, nothing) != nothing
|
||||
for esym in (:xerror, :yerror, :zerror)
|
||||
if get(kw, esym, nothing) !== nothing
|
||||
# we make a copy of the KW and apply an errorbar recipe
|
||||
errkw = copy(kw)
|
||||
errkw[:seriestype] = esym
|
||||
@@ -145,76 +116,76 @@ function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
|
||||
end
|
||||
end
|
||||
|
||||
function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
|
||||
function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW)
|
||||
# handle smoothing by adding a new series
|
||||
if get(kw, :smooth, false)
|
||||
x, y = kw[:x], kw[:y]
|
||||
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
|
||||
sx = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
||||
sy = β * sx + α
|
||||
push!(kw_list, merge(copy(kw), KW(
|
||||
:seriestype => :path,
|
||||
:x => sx,
|
||||
:y => sy,
|
||||
:fillrange => nothing,
|
||||
:label => "",
|
||||
:primary => false,
|
||||
)))
|
||||
sy = β .* sx .+ α
|
||||
push!(
|
||||
kw_list,
|
||||
merge(
|
||||
copy(kw),
|
||||
KW(
|
||||
:seriestype => :path,
|
||||
:x => sx,
|
||||
:y => sy,
|
||||
:fillrange => nothing,
|
||||
:label => "",
|
||||
:primary => false,
|
||||
),
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# plot recipes
|
||||
|
||||
# Grab the first in line to be processed and pass it through apply_recipe
|
||||
# to generate a list of RecipeData objects (data + attributes).
|
||||
# If we applied a "plot recipe" without error, then add the returned datalist's KWs,
|
||||
# otherwise we just add the original KW.
|
||||
function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_process::Vector{KW})
|
||||
if !isa(get(kw, :seriestype, nothing), Symbol)
|
||||
# seriestype was never set, or it's not a Symbol, so it can't be a plot recipe
|
||||
push!(kw_list, kw)
|
||||
return
|
||||
end
|
||||
try
|
||||
st = kw[:seriestype]
|
||||
st = kw[:seriestype] = get(_typeAliases, st, st)
|
||||
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
|
||||
for data in datalist
|
||||
preprocessArgs!(data.d)
|
||||
if data.d[:seriestype] == st
|
||||
error("Plot recipe $st returned the same seriestype: $(data.d)")
|
||||
end
|
||||
push!(still_to_process, data.d)
|
||||
end
|
||||
catch err
|
||||
if isa(err, MethodError)
|
||||
push!(kw_list, kw)
|
||||
else
|
||||
rethrow()
|
||||
RecipesPipeline.get_axis_limits(plt::Plot, letter) = axis_limits(plt[1], letter, false)
|
||||
|
||||
|
||||
## Plot recipes
|
||||
|
||||
RecipesPipeline.type_alias(plt::Plot) = get(_typeAliases, st, st)
|
||||
|
||||
|
||||
## Plot setup
|
||||
|
||||
function RecipesPipeline.plot_setup!(plt::Plot, plotattributes, kw_list)
|
||||
_plot_setup(plt, plotattributes, kw_list)
|
||||
_subplot_setup(plt, plotattributes, kw_list)
|
||||
return nothing
|
||||
end
|
||||
|
||||
function RecipesPipeline.process_sliced_series_attributes!(plt::Plots.Plot, kw_list)
|
||||
# swap errors
|
||||
err_inds = findall(kw -> get(kw, :seriestype, :path) in (:xerror, :yerror, :zerror), kw_list)
|
||||
for ind in err_inds
|
||||
if get(kw_list[ind-1],:seriestype,:path) == :scatter
|
||||
tmp = copy(kw_list[ind])
|
||||
kw_list[ind] = copy(kw_list[ind-1])
|
||||
kw_list[ind-1] = tmp
|
||||
end
|
||||
end
|
||||
return
|
||||
return nothing
|
||||
end
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# setup plot and subplot
|
||||
|
||||
function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
# TODO: Should some of this logic be moved to RecipesPipeline?
|
||||
function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
||||
# merge in anything meant for the Plot
|
||||
for kw in kw_list, (k,v) in kw
|
||||
haskey(_plot_defaults, k) && (d[k] = pop!(kw, k))
|
||||
for kw in kw_list, (k, v) in kw
|
||||
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
|
||||
end
|
||||
|
||||
# TODO: init subplots here
|
||||
_update_plot_args(plt, d)
|
||||
_update_plot_args(plt, plotattributes)
|
||||
if !plt.init
|
||||
plt.o = Base.invokelatest(_create_backend_figure, plt)
|
||||
|
||||
# create the layout and subplots from the inputs
|
||||
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
for (idx, sp) in enumerate(plt.subplots)
|
||||
sp.plt = plt
|
||||
sp.attr[:subplot_index] = idx
|
||||
end
|
||||
@@ -225,7 +196,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
|
||||
# handle inset subplots
|
||||
insets = plt[:inset_subplots]
|
||||
if insets != nothing
|
||||
if insets !== nothing
|
||||
if !(typeof(insets) <: AVec)
|
||||
insets = [insets]
|
||||
end
|
||||
@@ -239,7 +210,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
else
|
||||
parent = plt.layout
|
||||
end
|
||||
sp = Subplot(backend(), parent=parent)
|
||||
sp = Subplot(backend(), parent = parent)
|
||||
sp.plt = plt
|
||||
push!(plt.subplots, sp)
|
||||
push!(plt.inset_subplots, sp)
|
||||
@@ -250,33 +221,39 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
plt[:inset_subplots] = nothing
|
||||
end
|
||||
|
||||
function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
||||
# we'll keep a map of subplot to an attribute override dict.
|
||||
# Subplot/Axis attributes set by a user/series recipe apply only to the
|
||||
# Subplot object which they belong to.
|
||||
# TODO: allow matrices to still apply to all subplots
|
||||
sp_attrs = Dict{Subplot,Any}()
|
||||
sp_attrs = Dict{Subplot, Any}()
|
||||
for kw in kw_list
|
||||
# get the Subplot object to which the series belongs.
|
||||
sps = get(kw, :subplot, :auto)
|
||||
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
|
||||
sp = get_subplot(
|
||||
plt,
|
||||
_cycle(
|
||||
sps == :auto ? plt.subplots : plt.subplots[sps],
|
||||
series_idx(kw_list, kw),
|
||||
),
|
||||
)
|
||||
kw[:subplot] = sp
|
||||
|
||||
# extract subplot/axis attributes from kw and add to sp_attr
|
||||
attr = KW()
|
||||
for (k,v) in collect(kw)
|
||||
if haskey(_subplot_defaults, k) || haskey(_axis_defaults_byletter, k)
|
||||
for (k, v) in collect(kw)
|
||||
if is_subplot_attr(k) || is_axis_attr(k)
|
||||
attr[k] = pop!(kw, k)
|
||||
end
|
||||
if haskey(_axis_defaults, k)
|
||||
if is_axis_attr_noletter(k)
|
||||
v = pop!(kw, k)
|
||||
for letter in (:x,:y,:z)
|
||||
attr[Symbol(letter,k)] = v
|
||||
for letter in (:x, :y, :z)
|
||||
attr[Symbol(letter, k)] = v
|
||||
end
|
||||
end
|
||||
for k in (:scale,), letter in (:x,:y,:z)
|
||||
for k in (:scale,), letter in (:x, :y, :z)
|
||||
# Series recipes may need access to this information
|
||||
lk = Symbol(letter,k)
|
||||
lk = Symbol(letter, k)
|
||||
if haskey(attr, lk)
|
||||
kw[lk] = attr[lk]
|
||||
end
|
||||
@@ -286,9 +263,9 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
end
|
||||
|
||||
# override subplot/axis args. `sp_attrs` take precendence
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
attr = if !haskey(d, :subplot) || d[:subplot] == idx
|
||||
merge(d, get(sp_attrs, sp, KW()))
|
||||
for (idx, sp) in enumerate(plt.subplots)
|
||||
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx
|
||||
merge(plotattributes, get(sp_attrs, sp, KW()))
|
||||
else
|
||||
get(sp_attrs, sp, KW())
|
||||
end
|
||||
@@ -299,18 +276,44 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
link_axes!(plt.layout, plt[:link])
|
||||
end
|
||||
|
||||
function series_idx(kw_list::AVec{KW}, kw::AKW)
|
||||
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
||||
end
|
||||
|
||||
|
||||
## Series recipes
|
||||
|
||||
function RecipesPipeline.slice_series_attributes!(plt::Plot, kw_list, kw)
|
||||
sp::Subplot = kw[:subplot]
|
||||
# in series attributes given as vector with one element per series,
|
||||
# select the value for current series
|
||||
_slice_series_args!(kw, plt, sp, series_idx(kw_list, kw))
|
||||
return nothing
|
||||
end
|
||||
|
||||
RecipesPipeline.series_defaults(plt::Plot) = _series_defaults # in args.jl
|
||||
|
||||
RecipesPipeline.is_seriestype_supported(plt::Plot, st) = is_seriestype_supported(st)
|
||||
|
||||
function RecipesPipeline.add_series!(plt::Plot, plotattributes)
|
||||
sp = _prepare_subplot(plt, plotattributes)
|
||||
_expand_subplot_extrema(sp, plotattributes, plotattributes[:seriestype])
|
||||
_update_series_attributes!(plotattributes, plt, sp)
|
||||
_add_the_series(plt, sp, plotattributes)
|
||||
end
|
||||
|
||||
# getting ready to add the series... last update to subplot from anything
|
||||
# that might have been added during series recipes
|
||||
function _prepare_subplot(plt::Plot{T}, d::KW) where T
|
||||
st::Symbol = d[:seriestype]
|
||||
sp::Subplot{T} = d[:subplot]
|
||||
function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T}
|
||||
st::Symbol = plotattributes[:seriestype]
|
||||
sp::Subplot{T} = plotattributes[:subplot]
|
||||
sp_idx = get_subplot_index(plt, sp)
|
||||
_update_subplot_args(plt, sp, d, sp_idx, true)
|
||||
_update_subplot_args(plt, sp, plotattributes, sp_idx, true)
|
||||
|
||||
st = _override_seriestype_check(d, st)
|
||||
st = _override_seriestype_check(plotattributes, st)
|
||||
|
||||
# change to a 3d projection for this subplot?
|
||||
if is3d(st)
|
||||
if RecipesPipeline.needs_3d_axes(st) || (st == :quiver && plotattributes[:z] !== nothing)
|
||||
sp.attr[:projection] = "3d"
|
||||
end
|
||||
|
||||
@@ -322,46 +325,36 @@ function _prepare_subplot(plt::Plot{T}, d::KW) where T
|
||||
sp
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# series types
|
||||
|
||||
function _override_seriestype_check(d::KW, st::Symbol)
|
||||
function _override_seriestype_check(plotattributes::AKW, st::Symbol)
|
||||
# do we want to override the series type?
|
||||
if !is3d(st) && !(st in (:contour,:contour3d))
|
||||
z = d[:z]
|
||||
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
|
||||
if !RecipesPipeline.is3d(st) && !(st in (:contour, :contour3d, :quiver))
|
||||
z = plotattributes[:z]
|
||||
if z !== nothing &&
|
||||
(size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
|
||||
st = (st == :scatter ? :scatter3d : :path3d)
|
||||
d[:seriestype] = st
|
||||
plotattributes[:seriestype] = st
|
||||
end
|
||||
end
|
||||
st
|
||||
end
|
||||
|
||||
function _prepare_annotations(sp::Subplot, d::KW)
|
||||
# strip out series annotations (those which are based on series x/y coords)
|
||||
# and add them to the subplot attr
|
||||
sp_anns = annotations(sp[:annotations])
|
||||
# series_anns = annotations(pop!(d, :series_annotations, []))
|
||||
# if isa(series_anns, SeriesAnnotations)
|
||||
# series_anns.x = d[:x]
|
||||
# series_anns.y = d[:y]
|
||||
# elseif length(series_anns) > 0
|
||||
# x, y = d[:x], d[:y]
|
||||
# nx, ny, na = map(length, (x,y,series_anns))
|
||||
# n = max(nx, ny, na)
|
||||
# series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
|
||||
# end
|
||||
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
||||
function needs_any_3d_axes(sp::Subplot)
|
||||
any(
|
||||
RecipesPipeline.needs_3d_axes(
|
||||
_override_seriestype_check(s.plotattributes, s.plotattributes[:seriestype])
|
||||
) for s in series_list(sp)
|
||||
)
|
||||
end
|
||||
|
||||
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
|
||||
# adjust extrema and discrete info
|
||||
if st == :image
|
||||
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
|
||||
xmin, xmax = ignorenan_extrema(plotattributes[:x])
|
||||
ymin, ymax = ignorenan_extrema(plotattributes[:y])
|
||||
expand_extrema!(sp[:xaxis], (xmin, xmax))
|
||||
expand_extrema!(sp[:yaxis], (ymin, ymax))
|
||||
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
|
||||
expand_extrema!(sp, d)
|
||||
elseif !(st in (:histogram, :bins2d, :histogram2d))
|
||||
expand_extrema!(sp, plotattributes)
|
||||
end
|
||||
# expand for zerolines (axes through origin)
|
||||
if sp[:framestyle] in (:origin, :zerolines)
|
||||
@@ -370,54 +363,24 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
function _add_the_series(plt, sp, d)
|
||||
warnOnUnsupported_args(plt.backend, d)
|
||||
warnOnUnsupported(plt.backend, d)
|
||||
series = Series(d)
|
||||
function _add_the_series(plt, sp, plotattributes)
|
||||
extra_kwargs = warn_on_unsupported_args(plt.backend, plotattributes)
|
||||
if (kw = plt[:extra_kwargs]) isa AbstractDict
|
||||
plt[:extra_plot_kwargs] = get(kw,:plot,KW())
|
||||
sp[:extra_kwargs] = get(kw,:subplot, KW())
|
||||
plotattributes[:extra_kwargs] = get(kw,:series,KW())
|
||||
elseif plt[:extra_kwargs] == :plot
|
||||
plt[:extra_plot_kwargs] = extra_kwargs
|
||||
elseif plt[:extra_kwargs] == :subplot
|
||||
sp[:extra_kwargs] = extra_kwargs
|
||||
elseif plt[:extra_kwargs] == :series
|
||||
plotattributes[:extra_kwargs] = extra_kwargs
|
||||
else
|
||||
ArgumentError("Unsupported type for extra keyword arguments")
|
||||
end
|
||||
warn_on_unsupported(plt.backend, plotattributes)
|
||||
series = Series(plotattributes)
|
||||
push!(plt.series_list, series)
|
||||
push!(sp.series_list, series)
|
||||
_series_added(plt, series)
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
|
||||
# this method recursively applies series recipes when the seriestype is not supported
|
||||
# natively by the backend
|
||||
function _process_seriesrecipe(plt::Plot, d::KW)
|
||||
# replace seriestype aliases
|
||||
st = Symbol(d[:seriestype])
|
||||
st = d[:seriestype] = get(_typeAliases, st, st)
|
||||
|
||||
# shapes shouldn't have fillrange set
|
||||
if d[:seriestype] == :shape
|
||||
d[:fillrange] = nothing
|
||||
end
|
||||
|
||||
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
|
||||
if is_seriestype_supported(st)
|
||||
sp = _prepare_subplot(plt, d)
|
||||
_prepare_annotations(sp, d)
|
||||
_expand_subplot_extrema(sp, d, st)
|
||||
_update_series_attributes!(d, plt, sp)
|
||||
_add_the_series(plt, sp, d)
|
||||
|
||||
else
|
||||
# get a sub list of series for this seriestype
|
||||
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
|
||||
|
||||
# assuming there was no error, recursively apply the series recipes
|
||||
for data in datalist
|
||||
if isa(data, RecipeData)
|
||||
preprocessArgs!(data.d)
|
||||
if data.d[:seriestype] == st
|
||||
error("The seriestype didn't change in series recipe $st. This will cause a StackOverflow.")
|
||||
end
|
||||
_process_seriesrecipe(plt, data.d)
|
||||
else
|
||||
warn("Unhandled recipe: $(data)")
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
nothing
|
||||
end
|
||||
|
||||
+81
-120
@@ -1,10 +1,10 @@
|
||||
|
||||
mutable struct CurrentPlot
|
||||
nullableplot::Nullable{AbstractPlot}
|
||||
nullableplot::Union{AbstractPlot, Nothing}
|
||||
end
|
||||
const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
|
||||
const CURRENT_PLOT = CurrentPlot(nothing)
|
||||
|
||||
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
|
||||
isplotnull() = CURRENT_PLOT.nullableplot === nothing
|
||||
|
||||
"""
|
||||
current()
|
||||
@@ -14,16 +14,47 @@ function current()
|
||||
if isplotnull()
|
||||
error("No current plot/subplot")
|
||||
end
|
||||
get(CURRENT_PLOT.nullableplot)
|
||||
CURRENT_PLOT.nullableplot
|
||||
end
|
||||
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = Nullable(plot))
|
||||
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}"
|
||||
Base.print(io::IO, plt::Plot) = print(io, string(plt))
|
||||
Base.show(io::IO, plt::Plot) = print(io, string(plt))
|
||||
function Base.show(io::IO, plt::Plot)
|
||||
print(io, string(plt))
|
||||
sp_ekwargs = getindex.(plt.subplots, :extra_kwargs)
|
||||
s_ekwargs = getindex.(plt.series_list, :extra_kwargs)
|
||||
if isempty(plt[:extra_plot_kwargs]) && all(isempty, sp_ekwargs) && all(isempty, s_ekwargs)
|
||||
return
|
||||
end
|
||||
print(io,"\nCaptured extra kwargs:\n")
|
||||
do_show = true
|
||||
for (key, value) in plt[:extra_plot_kwargs]
|
||||
do_show && println(io, " Plot:")
|
||||
println(io, " "^4, key, ": ", value)
|
||||
do_show = false
|
||||
end
|
||||
do_show = true
|
||||
for (i, ekwargs) in enumerate(sp_ekwargs)
|
||||
for (key, value) in ekwargs
|
||||
do_show && println(io, " SubplotPlot{$i}:")
|
||||
println(io, " "^4, key, ": ", value)
|
||||
do_show = false
|
||||
end
|
||||
do_show = true
|
||||
end
|
||||
for (i, ekwargs) in enumerate(s_ekwargs)
|
||||
for (key, value) in ekwargs
|
||||
do_show && println(io, " Series{$i}:")
|
||||
println(io, " "^4, key, ": ", value)
|
||||
do_show = false
|
||||
end
|
||||
do_show = true
|
||||
end
|
||||
end
|
||||
|
||||
getplot(plt::Plot) = plt
|
||||
getattr(plt::Plot, idx::Int = 1) = plt.attr
|
||||
@@ -43,37 +74,40 @@ The main plot command. Use `plot` to create a new plot object, and `plot!` to ad
|
||||
|
||||
There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected.
|
||||
When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr([attr])`
|
||||
function, where `attr` is the symbol `:Series:`, `:Subplot:`, `:Plot` or `:Axis`. Pass any attribute to `plotattr`
|
||||
as a String to look up its docstring; e.g. `plotattr("seriestype")`.
|
||||
function, where `attr` is the symbol `:Series`, `:Subplot`, `:Plot`, or `:Axis`. Pass any attribute to `plotattr`
|
||||
as a String to look up its docstring, e.g., `plotattr("seriestype")`.
|
||||
"""
|
||||
|
||||
# this creates a new plot with args/kw and sets it to be the current plot
|
||||
function plot(args...; kw...)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
@nospecialize
|
||||
# this creates a new plot with args/kw and sets it to be the current plot
|
||||
plotattributes = KW(kw)
|
||||
RecipesPipeline.preprocess_attributes!(plotattributes)
|
||||
|
||||
# create an empty Plot then process
|
||||
plt = Plot()
|
||||
# plt.user_attr = d
|
||||
_plot!(plt, d, args)
|
||||
# plt.user_attr = plotattributes
|
||||
_plot!(plt, plotattributes, args)
|
||||
end
|
||||
|
||||
# build a new plot from existing plots
|
||||
# note: we split into plt1 and plts_tail so we can dispatch correctly
|
||||
function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
# note: we split into plt1, plt2 and plts_tail so we can dispatch correctly
|
||||
plot(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) = plot!(deepcopy(plt1), deepcopy(plt2), deepcopy.(plts_tail)...; kw...)
|
||||
function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
|
||||
@nospecialize
|
||||
plotattributes = KW(kw)
|
||||
RecipesPipeline.preprocess_attributes!(plotattributes)
|
||||
|
||||
# build our plot vector from the args
|
||||
n = length(plts_tail) + 1
|
||||
plts = Array{Plot}(n)
|
||||
n = length(plts_tail) + 2
|
||||
plts = Array{Plot}(undef, n)
|
||||
plts[1] = plt1
|
||||
plts[2] = plt2
|
||||
for (i,plt) in enumerate(plts_tail)
|
||||
plts[i+1] = plt
|
||||
plts[i+2] = plt
|
||||
end
|
||||
|
||||
# compute the layout
|
||||
layout = layout_args(d, n)[1]
|
||||
layout = layout_args(plotattributes, n)[1]
|
||||
num_sp = sum([length(p.subplots) for p in plts])
|
||||
|
||||
# create a new plot object, with subplot list/map made of existing subplots.
|
||||
@@ -84,21 +118,21 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
# TODO: build the user_attr dict by creating "Any matrices" for the args of each subplot
|
||||
|
||||
# TODO: replace this with proper processing from a merged user_attr KW
|
||||
# update plot args, first with existing plots, then override with d
|
||||
# update plot args, first with existing plots, then override with plotattributes
|
||||
for p in plts
|
||||
_update_plot_args(plt, copy(p.attr))
|
||||
plt.n += p.n
|
||||
end
|
||||
_update_plot_args(plt, d)
|
||||
_update_plot_args(plt, plotattributes)
|
||||
|
||||
# pass new plot to the backend
|
||||
plt.o = _create_backend_figure(plt)
|
||||
plt.init = true
|
||||
|
||||
series_attr = KW()
|
||||
for (k,v) in d
|
||||
if haskey(_series_defaults, k)
|
||||
series_attr[k] = pop!(d,k)
|
||||
for (k,v) in plotattributes
|
||||
if is_series_attr(k)
|
||||
series_attr[k] = pop!(plotattributes,k)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -119,8 +153,8 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
sp.plt = plt
|
||||
sp.attr[:subplot_index] = idx
|
||||
for series in serieslist
|
||||
merge!(series.d, series_attr)
|
||||
_add_defaults!(series.d, plt, sp, cmdidx)
|
||||
merge!(series.plotattributes, series_attr)
|
||||
_slice_series_args!(series.plotattributes, plt, sp, cmdidx)
|
||||
push!(plt.series_list, series)
|
||||
_series_added(plt, series)
|
||||
cmdidx += 1
|
||||
@@ -129,19 +163,20 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
|
||||
# first apply any args for the subplots
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
_update_subplot_args(plt, sp, d, idx, false)
|
||||
_update_subplot_args(plt, sp, plotattributes, idx, false)
|
||||
end
|
||||
|
||||
# finish up
|
||||
current(plt)
|
||||
_do_plot_show(plt, get(d, :show, default(:show)))
|
||||
_do_plot_show(plt, get(plotattributes, :show, default(:show)))
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
|
||||
# this adds to the current plot, or creates a new plot if none are current
|
||||
function plot!(args...; kw...)
|
||||
function plot!(args...; kw...)
|
||||
@nospecialize
|
||||
local plt
|
||||
try
|
||||
plt = current()
|
||||
@@ -152,11 +187,13 @@ function plot!(args...; kw...)
|
||||
end
|
||||
|
||||
# this adds to a specific plot... most plot commands will flow through here
|
||||
plot(plt::Plot, args...; kw...) = plot!(deepcopy(plt), args...; kw...)
|
||||
function plot!(plt::Plot, args...; kw...)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
# merge!(plt.user_attr, d)
|
||||
_plot!(plt, d, args)
|
||||
@nospecialize
|
||||
plotattributes = KW(kw)
|
||||
RecipesPipeline.preprocess_attributes!(plotattributes)
|
||||
# merge!(plt.user_attr, plotattributes)
|
||||
_plot!(plt, plotattributes, args)
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
@@ -164,88 +201,12 @@ end
|
||||
# this is the core plotting function. recursively apply recipes to build
|
||||
# a list of series KW dicts.
|
||||
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
|
||||
function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
d[:plot_object] = plt
|
||||
|
||||
if !isempty(args) && !isdefined(Main, :StatPlots) &&
|
||||
first(split(string(typeof(args[1])), ".")) == "DataFrames"
|
||||
warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
|
||||
end
|
||||
|
||||
# --------------------------------
|
||||
# "USER RECIPES"
|
||||
# --------------------------------
|
||||
|
||||
kw_list = _process_userrecipes(plt, d, args)
|
||||
|
||||
# info(1)
|
||||
# map(DD, kw_list)
|
||||
|
||||
|
||||
# --------------------------------
|
||||
# "PLOT RECIPES"
|
||||
# --------------------------------
|
||||
|
||||
# "plot recipe", which acts like a series type, and is processed before
|
||||
# the plot layout is created, which allows for setting layouts and other plot-wide attributes.
|
||||
# we get inputs which have been fully processed by "user recipes" and "type recipes",
|
||||
# so we can expect standard vectors, surfaces, etc. No defaults have been set yet.
|
||||
still_to_process = kw_list
|
||||
kw_list = KW[]
|
||||
while !isempty(still_to_process)
|
||||
next_kw = shift!(still_to_process)
|
||||
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
|
||||
end
|
||||
|
||||
# info(2)
|
||||
# map(DD, kw_list)
|
||||
|
||||
# --------------------------------
|
||||
# Plot/Subplot/Layout setup
|
||||
# --------------------------------
|
||||
_plot_setup(plt, d, kw_list)
|
||||
_subplot_setup(plt, d, kw_list)
|
||||
|
||||
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
|
||||
# !!! The next step is to recursively apply series recipes until the backend supports that series type !!!
|
||||
|
||||
# --------------------------------
|
||||
# "SERIES RECIPES"
|
||||
# --------------------------------
|
||||
|
||||
# info(3)
|
||||
# map(DD, kw_list)
|
||||
|
||||
for kw in kw_list
|
||||
sp::Subplot = kw[:subplot]
|
||||
# idx = get_subplot_index(plt, sp)
|
||||
|
||||
# # we update subplot args in case something like the color palatte is part of the recipe
|
||||
# _update_subplot_args(plt, sp, kw, idx, true)
|
||||
|
||||
# set default values, select from attribute cycles, and generally set the final attributes
|
||||
_add_defaults!(kw, plt, sp, command_idx(kw_list,kw))
|
||||
|
||||
# now we have a fully specified series, with colors chosen. we must recursively handle
|
||||
# series recipes, which dispatch on seriestype. If a backend does not natively support a seriestype,
|
||||
# we check for a recipe that will convert that series type into one made up of lower-level components.
|
||||
# For example, a histogram is just a bar plot with binned data, a bar plot is really a filled step plot,
|
||||
# and a step plot is really just a path. So any backend that supports drawing a path will implicitly
|
||||
# be able to support step, bar, and histogram plots (and any recipes that use those components).
|
||||
_process_seriesrecipe(plt, kw)
|
||||
end
|
||||
|
||||
# --------------------------------
|
||||
|
||||
function _plot!(plt::Plot, plotattributes, args)
|
||||
@nospecialize
|
||||
RecipesPipeline.recipe_pipeline!(plt, plotattributes, args)
|
||||
current(plt)
|
||||
|
||||
# do we want to force display?
|
||||
# if plt[:show]
|
||||
# gui(plt)
|
||||
# end
|
||||
_do_plot_show(plt, plt[:show])
|
||||
|
||||
plt
|
||||
return plt
|
||||
end
|
||||
|
||||
|
||||
@@ -283,12 +244,12 @@ end
|
||||
# plot to a Subplot
|
||||
|
||||
function plot(sp::Subplot, args...; kw...)
|
||||
@nospecialize
|
||||
plt = sp.plt
|
||||
plot(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
|
||||
plot(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
|
||||
end
|
||||
function plot!(sp::Subplot, args...; kw...)
|
||||
@nospecialize
|
||||
plt = sp.plt
|
||||
plot!(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
|
||||
plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
+17
-9
@@ -18,7 +18,7 @@ end
|
||||
plotattr([attr])
|
||||
|
||||
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
|
||||
The information is the same as that given on https://juliaplots.github.io/attributes/.
|
||||
The information is the same as that given on https://docs.juliaplots.org/latest/attributes/.
|
||||
"""
|
||||
function plotattr()
|
||||
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
|
||||
@@ -40,23 +40,31 @@ function plotattr(attribute::AbstractString)
|
||||
error("There is no attribute named $attribute")
|
||||
end
|
||||
|
||||
printnothing(x) = x
|
||||
printnothing(x::Nothing) = "nothing"
|
||||
|
||||
function plotattr(attrtype::Symbol, attribute::AbstractString)
|
||||
in(attrtype, keys(_attribute_defaults)) || ArgumentError("`attrtype` must match one of $(attrtypes())")
|
||||
|
||||
attribute = Symbol(lookup_aliases(attrtype, attribute))
|
||||
|
||||
desc = get(_arg_desc, attribute, "")
|
||||
first_period_idx = findfirst(desc, '.')
|
||||
typedesc = desc[1:first_period_idx-1]
|
||||
desc = strip(desc[first_period_idx+1:end])
|
||||
als = keys(filter((_,v)->v==attribute, _keyAliases)) |> collect |> sort
|
||||
first_period_idx = findfirst(isequal('.'), desc)
|
||||
if isnothing(first_period_idx)
|
||||
typedesc = ""
|
||||
desc = strip(desc)
|
||||
else
|
||||
typedesc = desc[1:first_period_idx-1]
|
||||
desc = strip(desc[first_period_idx+1:end])
|
||||
end
|
||||
als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort
|
||||
als = join(map(string,als), ", ")
|
||||
def = _attribute_defaults[attrtype][attribute]
|
||||
|
||||
|
||||
# Looks up the different elements and plots them
|
||||
println("$attribute ", typedesc == "" ? "" : "{$typedesc}", "\n",
|
||||
als == "" ? "" : "$als\n",
|
||||
"\n$desc\n",
|
||||
"$(attrtype) attribute, ", def == "" ? "" : " default: $def")
|
||||
println("$(printnothing(attribute)) ", typedesc == "" ? "" : "{$(printnothing(typedesc))}", "\n",
|
||||
als == "" ? "" : "$(printnothing(als))\n",
|
||||
"\n$(printnothing(desc))\n",
|
||||
"$(printnothing(attrtype)) attribute, ", def == "" ? "" : " default: $(printnothing(def))")
|
||||
end
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
function _precompile_()
|
||||
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
should_precompile = true
|
||||
|
||||
|
||||
# Don't edit the following! Instead change the script for `snoop_bot`.
|
||||
ismultios = false
|
||||
ismultiversion = false
|
||||
# precompile_enclosure
|
||||
@static if !should_precompile
|
||||
# nothing
|
||||
elseif !ismultios && !ismultiversion
|
||||
@static if isfile(joinpath(
|
||||
@__DIR__,
|
||||
"../deps/SnoopCompile/precompile/precompile_Plots.jl",
|
||||
))
|
||||
include("../deps/SnoopCompile/precompile/precompile_Plots.jl")
|
||||
_precompile_()
|
||||
end
|
||||
else
|
||||
|
||||
end # precompile_enclosure
|
||||
+885
-307
File diff suppressed because it is too large
Load Diff
-649
@@ -1,649 +0,0 @@
|
||||
|
||||
|
||||
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
|
||||
# Special handling for: no args, xmin/xmax, parametric, dataframes
|
||||
# Then once inputs have been converted, build the series args, map functions, etc.
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
|
||||
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(d, :seriestype, :none))
|
||||
|
||||
# unknown
|
||||
convertToAnyVector(x, d::KW) = error("No user recipe defined for $(typeof(x))")
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, d::KW)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
|
||||
|
||||
# volume
|
||||
convertToAnyVector(v::Volume, d::KW) = Any[v], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
|
||||
|
||||
# # dates
|
||||
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, d::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
|
||||
|
||||
|
||||
function convertToAnyVector(args...)
|
||||
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
|
||||
# result in that array being shared. push!, etc will add too many items to that array
|
||||
|
||||
compute_x(x::Void, y::Void, z) = 1:size(z,1)
|
||||
compute_x(x::Void, y, z) = 1:size(y,1)
|
||||
compute_x(x::Function, y, z) = map(x, y)
|
||||
compute_x(x, y, z) = copy(x)
|
||||
|
||||
# compute_y(x::Void, y::Function, z) = error()
|
||||
compute_y(x::Void, y::Void, z) = 1:size(z,2)
|
||||
compute_y(x, y::Function, z) = map(y, x)
|
||||
compute_y(x, y, z) = copy(y)
|
||||
|
||||
compute_z(x, y, z::Function) = map(z, x, y)
|
||||
compute_z(x, y, z::AbstractMatrix) = Surface(z)
|
||||
compute_z(x, y, z::Void) = nothing
|
||||
compute_z(x, y, z) = copy(z)
|
||||
|
||||
nobigs(v::AVec{BigFloat}) = map(Float64, v)
|
||||
nobigs(v::AVec{BigInt}) = map(Int64, v)
|
||||
nobigs(v) = v
|
||||
|
||||
@noinline function compute_xyz(x, y, z)
|
||||
x = compute_x(x,y,z)
|
||||
y = compute_y(x,y,z)
|
||||
z = compute_z(x,y,z)
|
||||
nobigs(x), nobigs(y), nobigs(z)
|
||||
end
|
||||
|
||||
# not allowed
|
||||
compute_xyz(x::Void, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
|
||||
compute_xyz(x::Void, y::Void, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
# we are going to build recipes to do the processing and splitting of the args
|
||||
|
||||
# ensure we dispatch to the slicer
|
||||
struct SliceIt end
|
||||
|
||||
# the catch-all recipes
|
||||
@recipe function f(::Type{SliceIt}, x, y, z)
|
||||
|
||||
# handle data with formatting attached
|
||||
if typeof(x) <: Formatted
|
||||
xformatter := x.formatter
|
||||
x = x.data
|
||||
end
|
||||
if typeof(y) <: Formatted
|
||||
yformatter := y.formatter
|
||||
y = y.data
|
||||
end
|
||||
if typeof(z) <: Formatted
|
||||
zformatter := z.formatter
|
||||
z = z.data
|
||||
end
|
||||
|
||||
xs, _ = convertToAnyVector(x, plotattributes)
|
||||
ys, _ = convertToAnyVector(y, plotattributes)
|
||||
zs, _ = convertToAnyVector(z, plotattributes)
|
||||
|
||||
fr = pop!(plotattributes, :fillrange, nothing)
|
||||
fillranges, _ = if typeof(fr) <: Number
|
||||
([fr],nothing)
|
||||
else
|
||||
convertToAnyVector(fr, plotattributes)
|
||||
end
|
||||
mf = length(fillranges)
|
||||
|
||||
rib = pop!(plotattributes, :ribbon, nothing)
|
||||
ribbons, _ = if typeof(rib) <: Number
|
||||
([fr],nothing)
|
||||
else
|
||||
convertToAnyVector(rib, plotattributes)
|
||||
end
|
||||
mr = length(ribbons)
|
||||
|
||||
# @show zs
|
||||
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
mz = length(zs)
|
||||
if mx > 0 && my > 0 && mz > 0
|
||||
for i in 1:max(mx, my, mz)
|
||||
# add a new series
|
||||
di = copy(plotattributes)
|
||||
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
|
||||
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
|
||||
|
||||
# handle fillrange
|
||||
fr = fillranges[mod1(i,mf)]
|
||||
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
|
||||
|
||||
# handle ribbons
|
||||
rib = ribbons[mod1(i,mr)]
|
||||
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
|
||||
|
||||
push!(series_list, RecipeData(di, ()))
|
||||
end
|
||||
end
|
||||
nothing # don't add a series for the main block
|
||||
end
|
||||
|
||||
# this is the default "type recipe"... just pass the object through
|
||||
@recipe f(::Type{T}, v::T) where {T<:Any} = v
|
||||
|
||||
# this should catch unhandled "series recipes" and error with a nice message
|
||||
@recipe f(::Type{V}, x, y, z) where {V<:Val} = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
|
||||
|
||||
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
|
||||
|
||||
# Handle type recipes when the recipe is defined on the elements.
|
||||
# This sort of recipe should return a pair of functions... one to convert to number,
|
||||
# and one to format tick values.
|
||||
function _apply_type_recipe(d, v::AbstractArray)
|
||||
isempty(v) && return Float64[]
|
||||
args = RecipesBase.apply_recipe(d, typeof(v[1]), v[1])[1].args
|
||||
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
|
||||
numfunc, formatter = args
|
||||
Formatted(map(numfunc, v), formatter)
|
||||
else
|
||||
v
|
||||
end
|
||||
end
|
||||
|
||||
# # special handling for Surface... need to properly unwrap and re-wrap
|
||||
# function _apply_type_recipe(d, v::Surface)
|
||||
# T = eltype(v.surf)
|
||||
# @show T
|
||||
# if T <: Integer || T <: AbstractFloat
|
||||
# v
|
||||
# else
|
||||
# ret = _apply_type_recipe(d, v.surf)
|
||||
# if typeof(ret) <: Formatted
|
||||
# Formatted(Surface(ret.data), ret.formatter)
|
||||
# else
|
||||
# v
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
# don't do anything for ints or floats
|
||||
_apply_type_recipe(d, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
|
||||
|
||||
# handle "type recipes" by converting inputs, and then either re-calling or slicing
|
||||
@recipe function f(x, y, z)
|
||||
did_replace = false
|
||||
newx = _apply_type_recipe(plotattributes, x)
|
||||
x === newx || (did_replace = true)
|
||||
newy = _apply_type_recipe(plotattributes, y)
|
||||
y === newy || (did_replace = true)
|
||||
newz = _apply_type_recipe(plotattributes, z)
|
||||
z === newz || (did_replace = true)
|
||||
if did_replace
|
||||
newx, newy, newz
|
||||
else
|
||||
SliceIt, x, y, z
|
||||
end
|
||||
end
|
||||
@recipe function f(x, y)
|
||||
did_replace = false
|
||||
newx = _apply_type_recipe(plotattributes, x)
|
||||
x === newx || (did_replace = true)
|
||||
newy = _apply_type_recipe(plotattributes, y)
|
||||
y === newy || (did_replace = true)
|
||||
if did_replace
|
||||
newx, newy
|
||||
else
|
||||
SliceIt, x, y, nothing
|
||||
end
|
||||
end
|
||||
@recipe function f(y)
|
||||
newy = _apply_type_recipe(plotattributes, y)
|
||||
if y !== newy
|
||||
newy
|
||||
else
|
||||
SliceIt, nothing, y, nothing
|
||||
end
|
||||
end
|
||||
|
||||
# if there's more than 3 inputs, it can't be passed directly to SliceIt
|
||||
# so we'll apply_type_recipe to all of them
|
||||
@recipe function f(v1, v2, v3, v4, vrest...)
|
||||
did_replace = false
|
||||
newargs = map(v -> begin
|
||||
newv = _apply_type_recipe(plotattributes, v)
|
||||
if newv !== v
|
||||
did_replace = true
|
||||
end
|
||||
newv
|
||||
end, (v1, v2, v3, v4, vrest...))
|
||||
if !did_replace
|
||||
error("Couldn't process recipe args: $(map(typeof, (v1, v2, v3, v4, vrest...)))")
|
||||
end
|
||||
newargs
|
||||
end
|
||||
|
||||
|
||||
# # --------------------------------------------------------------------
|
||||
# # 1 argument
|
||||
# # --------------------------------------------------------------------
|
||||
|
||||
# helper function to ensure relevant attributes are wrapped by Surface
|
||||
function wrap_surfaces(d::KW)
|
||||
if haskey(d, :fill_z)
|
||||
v = d[:fill_z]
|
||||
if !isa(v, Surface)
|
||||
d[:fill_z] = Surface(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
|
||||
|
||||
# return a surface if this is a 3d plot, otherwise let it be sliced up
|
||||
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat}
|
||||
if all3D(plotattributes)
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
SliceIt, nothing, mat, nothing
|
||||
end
|
||||
end
|
||||
|
||||
# if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface
|
||||
@recipe function f(fmt::Formatted{T}) where T<:AbstractMatrix
|
||||
if all3D(plotattributes)
|
||||
mat = fmt.data
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
|
||||
else
|
||||
SliceIt, nothing, fmt, nothing
|
||||
end
|
||||
end
|
||||
|
||||
# assume this is a Volume, so construct one
|
||||
@recipe function f(vol::AbstractArray{T,3}, args...) where T<:Number
|
||||
seriestype := :volume
|
||||
SliceIt, nothing, Volume(vol, args...), nothing
|
||||
end
|
||||
|
||||
|
||||
# # images - grays
|
||||
|
||||
@recipe function f(mat::AMat{T}) where T<:Gray
|
||||
n, m = size(mat)
|
||||
if is_seriestype_supported(:image)
|
||||
seriestype := :image
|
||||
yflip --> true
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
seriestype := :heatmap
|
||||
yflip --> true
|
||||
cbar --> false
|
||||
fillcolor --> ColorGradient([:black, :white])
|
||||
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
|
||||
end
|
||||
end
|
||||
|
||||
# # images - colors
|
||||
|
||||
@recipe function f(mat::AMat{T}) where T<:Colorant
|
||||
n, m = size(mat)
|
||||
|
||||
if is_seriestype_supported(:image)
|
||||
seriestype := :image
|
||||
yflip --> true
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
seriestype := :heatmap
|
||||
yflip --> true
|
||||
cbar --> false
|
||||
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
|
||||
SliceIt, 1:m, 1:n, Surface(z)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# # plotting arbitrary shapes/polygons
|
||||
|
||||
@recipe function f(shape::Shape)
|
||||
seriestype --> :shape
|
||||
coords(shape)
|
||||
end
|
||||
|
||||
@recipe function f(shapes::AVec{Shape})
|
||||
seriestype --> :shape
|
||||
coords(shapes)
|
||||
end
|
||||
|
||||
@recipe function f(shapes::AMat{Shape})
|
||||
seriestype --> :shape
|
||||
for j in 1:size(shapes,2)
|
||||
@series coords(vec(shapes[:,j]))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# function without range... use the current range of the x-axis
|
||||
|
||||
@recipe function f(f::FuncOrFuncs{F}) where F<:Function
|
||||
plt = plotattributes[:plot_object]
|
||||
xmin, xmax = try
|
||||
axis_limits(plt[1][:xaxis])
|
||||
catch
|
||||
xm = tryrange(f, [-5,-1,0,0.01])
|
||||
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
|
||||
end
|
||||
|
||||
f, xmin, xmax
|
||||
end
|
||||
|
||||
# try some intervals over which the function may be defined
|
||||
function tryrange(F::AbstractArray, vec)
|
||||
rets = [tryrange(f, vec) for f in F] # get the preferred for each
|
||||
maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all)
|
||||
rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there
|
||||
rets[1]
|
||||
end
|
||||
|
||||
function tryrange(F, vec)
|
||||
for v in vec
|
||||
try
|
||||
tmp = F(v)
|
||||
return v
|
||||
catch
|
||||
end
|
||||
end
|
||||
error("$F is not a Function, or is not defined at any of the values $vec")
|
||||
end
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # 2 arguments
|
||||
# # --------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # if functions come first, just swap the order (not to be confused with parametric functions...
|
||||
# # as there would be more than one function passed in)
|
||||
|
||||
@recipe function f(f::FuncOrFuncs{F}, x) where F<:Function
|
||||
F2 = typeof(x)
|
||||
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
|
||||
x, f
|
||||
end
|
||||
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # 3 arguments
|
||||
# # --------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # 3d line or scatter
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, z::AVec)
|
||||
# st = get(d, :seriestype, :none)
|
||||
# if st == :scatter
|
||||
# d[:seriestype] = :scatter3d
|
||||
# elseif !is3d(st)
|
||||
# d[:seriestype] = :path3d
|
||||
# end
|
||||
SliceIt, x, y, z
|
||||
end
|
||||
|
||||
@recipe function f(x::AMat, y::AMat, z::AMat)
|
||||
# st = get(d, :seriestype, :none)
|
||||
# if size(x) == size(y) == size(z)
|
||||
# if !is3d(st)
|
||||
# seriestype := :path3d
|
||||
# end
|
||||
# end
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, x, y, z
|
||||
end
|
||||
|
||||
#
|
||||
# # surface-like... function
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, zf::Function)
|
||||
# x = X <: Number ? sort(x) : x
|
||||
# y = Y <: Number ? sort(y) : y
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
||||
end
|
||||
|
||||
#
|
||||
# # surface-like... matrix grid
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, z::AMat)
|
||||
if !like_surface(get(plotattributes, :seriestype, :none))
|
||||
plotattributes[:seriestype] = :contour
|
||||
end
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, x, y, Surface(z)
|
||||
end
|
||||
|
||||
# # images - grays
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Gray
|
||||
if is_seriestype_supported(:image)
|
||||
seriestype := :image
|
||||
yflip --> true
|
||||
SliceIt, x, y, Surface(mat)
|
||||
else
|
||||
seriestype := :heatmap
|
||||
yflip --> true
|
||||
cbar --> false
|
||||
fillcolor --> ColorGradient([:black, :white])
|
||||
SliceIt, x, y, Surface(convert(Matrix{Float64}, mat))
|
||||
end
|
||||
end
|
||||
|
||||
# # images - colors
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Colorant
|
||||
if is_seriestype_supported(:image)
|
||||
seriestype := :image
|
||||
yflip --> true
|
||||
SliceIt, x, y, Surface(mat)
|
||||
else
|
||||
seriestype := :heatmap
|
||||
yflip --> true
|
||||
cbar --> false
|
||||
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
|
||||
SliceIt, x, y, Surface(z)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # Parametric functions
|
||||
# # --------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# # special handling... xmin/xmax with parametric function(s)
|
||||
@recipe function f(f::Function, xmin::Number, xmax::Number)
|
||||
xs = adapted_grid(f, (xmin, xmax))
|
||||
xs, f
|
||||
end
|
||||
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
|
||||
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
|
||||
xs, fs
|
||||
end
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, linspace(umin, umax, n)
|
||||
|
||||
#
|
||||
# # special handling... 3D parametric function(s)
|
||||
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
|
||||
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
|
||||
end
|
||||
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
|
||||
fx, fy, fz, linspace(umin, umax, numPoints)
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # Lists of tuples and FixedSizeArrays
|
||||
# # --------------------------------------------------------------------
|
||||
#
|
||||
# # if we get an unhandled tuple, just splat it in
|
||||
@recipe f(tup::Tuple) = tup
|
||||
|
||||
#
|
||||
# # (x,y) tuples
|
||||
@recipe f(xy::AVec{Tuple{R1,R2}}) where {R1<:Number,R2<:Number} = unzip(xy)
|
||||
@recipe f(xy::Tuple{R1,R2}) where {R1<:Number,R2<:Number} = [xy[1]], [xy[2]]
|
||||
|
||||
#
|
||||
# # (x,y,z) tuples
|
||||
@recipe f(xyz::AVec{Tuple{R1,R2,R3}}) where {R1<:Number,R2<:Number,R3<:Number} = unzip(xyz)
|
||||
@recipe f(xyz::Tuple{R1,R2,R3}) where {R1<:Number,R2<:Number,R3<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
|
||||
# these might be points+velocity, or OHLC or something else
|
||||
@recipe f(xyuv::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
|
||||
@recipe f(xyuv::Tuple{R1,R2,R3,R4}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
|
||||
|
||||
|
||||
#
|
||||
# # 2D FixedSizeArrays
|
||||
@recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
|
||||
@recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
|
||||
|
||||
#
|
||||
# # 3D FixedSizeArrays
|
||||
@recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
|
||||
@recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # handle grouping
|
||||
# # --------------------------------------------------------------------
|
||||
|
||||
# @recipe function f(groupby::GroupBy, args...)
|
||||
# for (i,glab) in enumerate(groupby.groupLabels)
|
||||
# # create a new series, with the label of the group, and an idxfilter (to be applied in slice_and_dice)
|
||||
# # TODO: use @series instead
|
||||
# @show i, glab, groupby.groupIds[i]
|
||||
# di = copy(d)
|
||||
# get!(di, :label, string(glab))
|
||||
# get!(di, :idxfilter, groupby.groupIds[i])
|
||||
# push!(series_list, RecipeData(di, args))
|
||||
# end
|
||||
# nothing
|
||||
# end
|
||||
|
||||
splittable_kw(key, val, lengthGroup) = false
|
||||
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
|
||||
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
|
||||
splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup)
|
||||
|
||||
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val)-1)...]
|
||||
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
|
||||
function split_kw(key, val::SeriesAnnotations, indices)
|
||||
split_strs = split_kw(key, val.strs, indices)
|
||||
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor)
|
||||
end
|
||||
|
||||
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
|
||||
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
|
||||
fill!(y_mat, def_val)
|
||||
for i in 1:length(groupby.groupLabels)
|
||||
xi = x[groupby.groupIds[i]]
|
||||
yi = y[groupby.groupIds[i]]
|
||||
y_mat[getindex.(x_ind, xi), i] = yi
|
||||
end
|
||||
return y_mat
|
||||
end
|
||||
|
||||
groupedvec2mat(x_ind, x, y::Tuple, groupby) = Tuple(groupedvec2mat(x_ind, x, v, groupby) for v in y)
|
||||
|
||||
group_as_matrix(t) = false
|
||||
|
||||
# split the group into 1 series per group, and set the label and idxfilter for each
|
||||
@recipe function f(groupby::GroupBy, args...)
|
||||
lengthGroup = maximum(union(groupby.groupIds...))
|
||||
if !(group_as_matrix(args[1]))
|
||||
for (i,glab) in enumerate(groupby.groupLabels)
|
||||
@series begin
|
||||
label --> string(glab)
|
||||
idxfilter --> groupby.groupIds[i]
|
||||
for (key,val) in plotattributes
|
||||
if splittable_kw(key, val, lengthGroup)
|
||||
:($key) := split_kw(key, val, groupby.groupIds[i])
|
||||
end
|
||||
end
|
||||
args
|
||||
end
|
||||
end
|
||||
else
|
||||
g = args[1]
|
||||
if length(g.args) == 1
|
||||
x = zeros(Int, lengthGroup)
|
||||
for indexes in groupby.groupIds
|
||||
x[indexes] = 1:length(indexes)
|
||||
end
|
||||
last_args = g.args
|
||||
else
|
||||
x = g.args[1]
|
||||
last_args = g.args[2:end]
|
||||
end
|
||||
x_u = unique(x)
|
||||
x_ind = Dict(zip(x_u, 1:length(x_u)))
|
||||
for (key,val) in plotattributes
|
||||
if splittable_kw(key, val, lengthGroup)
|
||||
:($key) := groupedvec2mat(x_ind, x, val, groupby)
|
||||
end
|
||||
end
|
||||
label --> reshape(groupby.groupLabels, 1, :)
|
||||
typeof(g)((x_u, (groupedvec2mat(x_ind, x, arg, groupby, NaN) for arg in last_args)...))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,484 @@
|
||||
@nospecialize
|
||||
|
||||
"""
|
||||
scatter(x,y)
|
||||
scatter!(x,y)
|
||||
|
||||
Make a scatter plot of y vs x.
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> scatter([1,2,3],[4,5,6],markersize=[3,4,5],markercolor=[:red,:green,:blue])
|
||||
julia> scatter([(1,4),(2,5),(3,6)])
|
||||
```
|
||||
"""
|
||||
@shorthands scatter
|
||||
|
||||
"""
|
||||
bar(x,y)
|
||||
bar!(x,y)
|
||||
|
||||
Make a bar plot of y vs x.
|
||||
|
||||
# Arguments
|
||||
|
||||
- $(_document_argument("bar_position"))
|
||||
- $(_document_argument("bar_width"))
|
||||
- $(_document_argument("bar_edges"))
|
||||
- $(_document_argument("orientation"))
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> bar([1,2,3],[4,5,6],fillcolor=[:red,:green,:blue],fillalpha=[0.2,0.4,0.6])
|
||||
julia> bar([(1,4),(2,5),(3,6)])
|
||||
```
|
||||
"""
|
||||
@shorthands bar
|
||||
|
||||
@shorthands barh
|
||||
|
||||
"""
|
||||
histogram(x)
|
||||
histogram!(x)
|
||||
|
||||
Plot a histogram.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `x`: AbstractVector of values to be binned
|
||||
- $(_document_argument("bins"))
|
||||
- `weights`: Vector of weights for the values in `x`, for weighted bin counts
|
||||
- $(_document_argument("normalize"))
|
||||
- $(_document_argument("bar_position"))
|
||||
- $(_document_argument("bar_width"))
|
||||
- $(_document_argument("bar_edges"))
|
||||
- $(_document_argument("orientation"))
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> histogram([1,2,1,1,4,3,8],bins=0:8)
|
||||
julia> histogram([1,2,1,1,4,3,8],bins=0:8,weights=weights([4,7,3,9,12,2,6]))
|
||||
```
|
||||
"""
|
||||
@shorthands histogram
|
||||
|
||||
"""
|
||||
barhist(x)
|
||||
barhist!(x)
|
||||
|
||||
Make a histogram bar plot. See `histogram`.
|
||||
"""
|
||||
@shorthands barhist
|
||||
|
||||
"""
|
||||
stephist(x)
|
||||
stephist!(x)
|
||||
|
||||
Make a histogram step plot (bin counts are represented using horizontal lines
|
||||
instead of bars). See `histogram`.
|
||||
"""
|
||||
@shorthands stephist
|
||||
|
||||
"""
|
||||
scatterhist(x)
|
||||
scatterhist!(x)
|
||||
|
||||
Make a histogram scatter plot (bin counts are represented using points
|
||||
instead of bars). See `histogram`.
|
||||
"""
|
||||
@shorthands scatterhist
|
||||
|
||||
"""
|
||||
histogram2d(x,y)
|
||||
histogram2d!(x,y)
|
||||
|
||||
Plot a two-dimensional histogram.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
|
||||
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
|
||||
its weight to the height of its bin.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> histogram2d(randn(10_000),randn(10_000))
|
||||
```
|
||||
"""
|
||||
@shorthands histogram2d
|
||||
|
||||
"""
|
||||
density(x)
|
||||
density!(x)
|
||||
|
||||
Make a line plot of a kernel density estimate of x.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `x`: AbstractVector of samples for probability density estimation
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> using StatsPlots
|
||||
julia> density(randn(100_000))
|
||||
```
|
||||
"""
|
||||
@shorthands density
|
||||
|
||||
"""
|
||||
heatmap(x,y,z)
|
||||
heatmap!(x,y,z)
|
||||
|
||||
Plot a heatmap of the rectangular array `z`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> heatmap(randn(10,10))
|
||||
```
|
||||
"""
|
||||
@shorthands heatmap
|
||||
@shorthands plots_heatmap
|
||||
|
||||
"""
|
||||
hexbin(x,y)
|
||||
hexbin!(x,y)
|
||||
|
||||
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
|
||||
with hexagonal bins)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> hexbin(randn(10_000), randn(10_000))
|
||||
```
|
||||
"""
|
||||
@shorthands hexbin
|
||||
|
||||
"""
|
||||
sticks(x,y)
|
||||
sticks!(x,y)
|
||||
|
||||
Draw a stick plot of y vs x.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> sticks(1:10)
|
||||
```
|
||||
"""
|
||||
@shorthands sticks
|
||||
|
||||
"""
|
||||
hline(y)
|
||||
hline!(y)
|
||||
|
||||
Draw horizontal lines at positions specified by the values in
|
||||
the AbstractVector `y`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> hline([-1,0,2])
|
||||
```
|
||||
"""
|
||||
@shorthands hline
|
||||
|
||||
"""
|
||||
vline(x)
|
||||
vline!(x)
|
||||
|
||||
Draw vertical lines at positions specified by the values in
|
||||
the AbstractVector `x`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> vline([-1,0,2])
|
||||
```
|
||||
"""
|
||||
@shorthands vline
|
||||
|
||||
"""
|
||||
hspan(y)
|
||||
|
||||
Draw a rectangle between the horizontal line at position `y[1]`
|
||||
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
|
||||
then further rectangles are drawn between `y[3]` and `y[4]`,
|
||||
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
|
||||
last entry of `y` is ignored.
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> hspan(1:6)
|
||||
```
|
||||
"""
|
||||
@shorthands hspan
|
||||
|
||||
"""
|
||||
vspan(x)
|
||||
|
||||
Draw a rectangle between the vertical line at position `x[1]`
|
||||
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
|
||||
then further rectangles are drawn between `x[3]` and `x[4]`,
|
||||
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
|
||||
last entry of `x` is ignored.
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> vspan(1:6)
|
||||
```
|
||||
"""
|
||||
@shorthands vspan
|
||||
|
||||
"""
|
||||
ohlc(x,y::Vector{OHLC})
|
||||
ohlc!(x,y::Vector{OHLC})
|
||||
|
||||
Make open-high-low-close plot. Each entry of y is represented by a vertical
|
||||
segment extending from the low value to the high value, with short horizontal
|
||||
segments on the left and right indicating the open and close values, respectively.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> meanprices = cumsum(randn(100))
|
||||
julia> y = OHLC[(p+rand(),p+1,p-1,p+rand()) for p in meanprices]
|
||||
julia> ohlc(y)
|
||||
```
|
||||
"""
|
||||
@shorthands ohlc
|
||||
|
||||
|
||||
"""
|
||||
contour(x,y,z)
|
||||
contour!(x,y,z)
|
||||
|
||||
Draw contour lines of the `Surface` z.
|
||||
|
||||
# Arguments
|
||||
- `levels`: Contour levels (if `AbstractVector`) or number of levels (if `Integer`)
|
||||
- `fill`: Bool. Fill area between contours or draw contours only (false by default)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> x = y = range(-20, stop = 20, length = 100)
|
||||
julia> contour(x, y, (x, y) -> x^2 + y^2)
|
||||
```
|
||||
"""
|
||||
@shorthands contour
|
||||
|
||||
"An alias for `contour` with fill = true."
|
||||
@shorthands contourf
|
||||
|
||||
|
||||
@shorthands contour3d
|
||||
|
||||
"""
|
||||
surface(x,y,z)
|
||||
surface!(x,y,z)
|
||||
|
||||
Draw a 3D surface plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> using LinearAlgebra
|
||||
julia> x = y = range(-3, stop = 3, length = 100)
|
||||
julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
|
||||
```
|
||||
"""
|
||||
@shorthands surface
|
||||
|
||||
"""
|
||||
wireframe(x,y,z)
|
||||
wireframe!(x,y,z)
|
||||
|
||||
Draw a 3D wireframe plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> wireframe(1:10,1:10,randn(10,10))
|
||||
```
|
||||
"""
|
||||
@shorthands wireframe
|
||||
|
||||
"""
|
||||
path3d(x,y,z)
|
||||
path3d!(x,y,z)
|
||||
|
||||
Plot a 3D path from `(x[1],y[1],z[1])` to `(x[2],y[2],z[2])`,
|
||||
..., to `(x[end],y[end],z[end])`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
```
|
||||
"""
|
||||
@shorthands path3d
|
||||
|
||||
"""
|
||||
scatter3d(x,y,z)
|
||||
scatter3d!(x,y,z)
|
||||
|
||||
Make a 3D scatter plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
```
|
||||
"""
|
||||
@shorthands scatter3d
|
||||
|
||||
"""
|
||||
mesh3d(x,y,z)
|
||||
mesh3d(x,y,z; connections)
|
||||
|
||||
Plot a 3d mesh. On Plotly the triangles can be specified using the connections argument.
|
||||
|
||||
# Example
|
||||
```Julia
|
||||
x=[0, 1, 2, 0]
|
||||
y=[0, 0, 1, 2]
|
||||
z=[0, 2, 0, 1]
|
||||
|
||||
i=[0, 0, 0, 1]
|
||||
j=[1, 2, 3, 2]
|
||||
k=[2, 3, 1, 3]
|
||||
|
||||
plot(x,y,z,seriestype=:mesh3d;connections=(i,j,k))
|
||||
```
|
||||
"""
|
||||
@shorthands mesh3d
|
||||
|
||||
"""
|
||||
boxplot(x, y)
|
||||
boxplot!(x, y)
|
||||
|
||||
Make a box and whisker plot.
|
||||
|
||||
# Keyword arguments
|
||||
- `notch`: Bool. Notch the box plot? (false)
|
||||
- `range`: Real. Values more than range*IQR below the first quartile
|
||||
or above the third quartile are shown as outliers (1.5)
|
||||
- `outliers`: Bool. Show outliers? (true)
|
||||
- `whisker_width`: Real or Symbol. Length of whiskers (:match)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> using StatsPlots
|
||||
julia> boxplot(repeat([1,2,3],outer=100),randn(300))
|
||||
```
|
||||
"""
|
||||
@shorthands boxplot
|
||||
|
||||
"""
|
||||
violin(x,y,z)
|
||||
violin!(x,y,z)
|
||||
|
||||
Make a violin plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> violin(repeat([1,2,3],outer=100),randn(300))
|
||||
```
|
||||
"""
|
||||
@shorthands violin
|
||||
|
||||
"""
|
||||
quiver(x,y,quiver=(u,v))
|
||||
quiver!(x,y,quiver=(u,v))
|
||||
|
||||
Make a quiver (vector field) plot. The `i`th vector extends
|
||||
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
|
||||
```
|
||||
"""
|
||||
@shorthands quiver
|
||||
|
||||
"""
|
||||
curves(x,y)
|
||||
curves!(x,y)
|
||||
|
||||
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
|
||||
with control points `(x[2],y[2]), ..., (x[end-1],y[end]-1)`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> curves([1,2,3,4],[1,1,2,4])
|
||||
```
|
||||
"""
|
||||
@shorthands curves
|
||||
|
||||
"Plot a pie diagram"
|
||||
@shorthands pie
|
||||
|
||||
"Plot with seriestype :path3d"
|
||||
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
|
||||
"Add title to an existing plot"
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
|
||||
"Add xlabel to an existing plot"
|
||||
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
|
||||
|
||||
"Add ylabel to an existing plot"
|
||||
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
|
||||
|
||||
"Set xlims for an existing plot"
|
||||
xlims!(lims::Tuple; kw...) = plot!(; xlims = lims, kw...)
|
||||
|
||||
"Set ylims for an existing plot"
|
||||
ylims!(lims::Tuple; kw...) = plot!(; ylims = lims, kw...)
|
||||
|
||||
"Set zlims for an existing plot"
|
||||
zlims!(lims::Tuple; kw...) = plot!(; zlims = lims, kw...)
|
||||
|
||||
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
|
||||
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
|
||||
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
|
||||
|
||||
|
||||
"Set xticks for an existing plot"
|
||||
xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...)
|
||||
|
||||
"Set yticks for an existing plot"
|
||||
yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...)
|
||||
|
||||
xticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
|
||||
yticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
|
||||
|
||||
"""
|
||||
annotate!(anns...)
|
||||
|
||||
Add annotations to an existing plot.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `anns`: An `AbstractVector` of tuples of the form `(x,y,text)`. The `text` object
|
||||
can be a `String`, `PlotText` PlotText (created with `text(args...)`),
|
||||
or a tuple of arguments to `text` (e.g., `("Label", 8, :red, :top)`).
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> plot(1:10)
|
||||
julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))])
|
||||
julia> annotate!([(4, 4, ("More text", 8, 45.0, :bottom, :red))])
|
||||
```
|
||||
"""
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!(anns::Tuple...; kw...) = plot!(; annotation = collect(anns), kw...)
|
||||
annotate!(anns::AVec{<:Tuple}; kw...) = plot!(; annotation = anns, kw...)
|
||||
|
||||
"Flip the current plots' x axis"
|
||||
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
|
||||
|
||||
"Flip the current plots' y axis"
|
||||
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
|
||||
"Specify y axis attributes for an existing plot"
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
|
||||
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
|
||||
|
||||
@specialize
|
||||
+21
-9
@@ -7,7 +7,7 @@ function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend
|
||||
(20mm, 5mm, 2mm, 10mm),
|
||||
defaultbox,
|
||||
defaultbox,
|
||||
KW(),
|
||||
DefaultsDict(KW(), _subplot_defaults),
|
||||
nothing,
|
||||
nothing
|
||||
)
|
||||
@@ -34,20 +34,32 @@ bottompad(sp::Subplot) = sp.minpad[4]
|
||||
get_subplot(plt::Plot, sp::Subplot) = sp
|
||||
get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
|
||||
get_subplot(plt::Plot, k) = plt.spmap[k]
|
||||
get_subplot(series::Series) = series.d[:subplot]
|
||||
get_subplot(series::Series) = series.plotattributes[:subplot]
|
||||
|
||||
get_subplot_index(plt::Plot, idx::Integer) = Int(idx)
|
||||
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(x -> x === sp, plt.subplots)
|
||||
|
||||
series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
series_list(sp::Subplot) = sp.series_list # filter(series -> series.plotattributes[:subplot] === sp, sp.plt.series_list)
|
||||
|
||||
function should_add_to_legend(series::Series)
|
||||
series.d[:primary] && series.d[:label] != "" &&
|
||||
!(series.d[:seriestype] in (
|
||||
:hexbin,:bins2d,:histogram2d,:hline,:vline,
|
||||
:contour,:contourf,:contour3d,:surface,:wireframe,
|
||||
:heatmap, :pie, :image
|
||||
))
|
||||
series.plotattributes[:primary] &&
|
||||
series.plotattributes[:label] != "" &&
|
||||
!(
|
||||
series.plotattributes[:seriestype] in (
|
||||
:hexbin,
|
||||
:bins2d,
|
||||
:histogram2d,
|
||||
:hline,
|
||||
:vline,
|
||||
:contour,
|
||||
:contourf,
|
||||
:contour3d,
|
||||
:surface,
|
||||
:wireframe,
|
||||
:heatmap,
|
||||
:image,
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
+28
-55
@@ -4,55 +4,25 @@
|
||||
Specify the colour theme for plots.
|
||||
"""
|
||||
function theme(s::Symbol; kw...)
|
||||
defaults = _get_defaults(s)
|
||||
defaults = copy(PlotThemes._themes[s].defaults)
|
||||
_theme(s, defaults; kw...)
|
||||
end
|
||||
|
||||
function _get_defaults(s::Symbol)
|
||||
thm = PlotThemes._themes[s]
|
||||
if :defaults in fieldnames(thm)
|
||||
return thm.defaults
|
||||
else # old PlotTheme type
|
||||
defaults = KW(
|
||||
:bg => thm.bg_secondary,
|
||||
:bginside => thm.bg_primary,
|
||||
:fg => thm.lines,
|
||||
:fgtext => thm.text,
|
||||
:fgguide => thm.text,
|
||||
:fglegend => thm.text,
|
||||
:palette => thm.palette,
|
||||
)
|
||||
if thm.gradient != nothing
|
||||
push!(defaults, :gradient => thm.gradient)
|
||||
end
|
||||
return defaults
|
||||
end
|
||||
end
|
||||
|
||||
function _theme(s::Symbol, defaults::KW; kw...)
|
||||
function _theme(s::Symbol, defaults::AKW; kw...)
|
||||
# Reset to defaults to overwrite active theme
|
||||
reset_defaults()
|
||||
|
||||
# Set the theme's gradient as default
|
||||
if haskey(defaults, :gradient)
|
||||
PlotUtils.clibrary(:misc)
|
||||
PlotUtils.default_cgrad(default = :sequential, sequential = PlotThemes.gradient_name(s))
|
||||
if haskey(defaults, :colorgradient)
|
||||
PlotUtils.default_cgrad(pop!(defaults, :colorgradient))
|
||||
else
|
||||
PlotUtils.clibrary(:Plots)
|
||||
PlotUtils.default_cgrad(default = :sequential, sequential = :inferno)
|
||||
PlotUtils.default_cgrad(:default)
|
||||
end
|
||||
|
||||
# maybe overwrite the theme's gradient
|
||||
kw = KW(kw)
|
||||
if haskey(kw, :gradient)
|
||||
kwgrad = pop!(kw, :gradient)
|
||||
for clib in clibraries()
|
||||
if kwgrad in cgradients(clib)
|
||||
PlotUtils.clibrary(clib)
|
||||
PlotUtils.default_cgrad(default = :sequential, sequential = kwgrad)
|
||||
break
|
||||
end
|
||||
end
|
||||
if haskey(kw, :colorgradient)
|
||||
PlotUtils.default_cgrad(pop!(kw, :colorgradient))
|
||||
end
|
||||
|
||||
# Set the theme's defaults
|
||||
@@ -74,33 +44,33 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
|
||||
@recipe function showtheme(st::ShowTheme)
|
||||
thm, cfunc = _get_showtheme_args(st.args...)
|
||||
defaults = _get_defaults(thm)
|
||||
defaults = PlotThemes._themes[thm].defaults
|
||||
|
||||
# get the gradient
|
||||
gradient_colors = get(defaults, :gradient, cgrad(:inferno).colors)
|
||||
gradient = cgrad(cfunc.(RGB.(gradient_colors)))
|
||||
gradient_colors = color_list(cgrad(get(defaults, :colorgradient, :default)))
|
||||
colorgradient = cgrad(cfunc.(RGB.(gradient_colors)))
|
||||
|
||||
# get the palette
|
||||
palette = get(defaults, :palette, get_color_palette(:auto, plot_color(:white), 17))
|
||||
palette = cfunc.(RGB.(palette))
|
||||
cp = color_list(palette(get(defaults, :palette, :default)))
|
||||
cp = cfunc.(RGB.(cp))
|
||||
|
||||
# apply the theme
|
||||
for k in keys(defaults)
|
||||
k in (:gradient, :palette) && continue
|
||||
k in (:colorgradient, :palette) && continue
|
||||
def = defaults[k]
|
||||
arg = get(_keyAliases, k, k)
|
||||
plotattributes[arg] = if typeof(def) <: Colorant
|
||||
cfunc(RGB(def))
|
||||
elseif eltype(def) <: Colorant
|
||||
cfunc.(RGB.(def))
|
||||
elseif contains(string(arg), "color")
|
||||
elseif occursin("color", string(arg))
|
||||
cfunc.(RGB.(plot_color.(def)))
|
||||
else
|
||||
def
|
||||
end
|
||||
end
|
||||
|
||||
srand(1)
|
||||
Random.seed!(1)
|
||||
|
||||
label := ""
|
||||
colorbar := false
|
||||
@@ -109,7 +79,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
for j in 1:4
|
||||
@series begin
|
||||
subplot := 1
|
||||
palette := palette
|
||||
color_palette := cp
|
||||
seriestype := :path
|
||||
cumsum(randn(50))
|
||||
end
|
||||
@@ -117,7 +87,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
@series begin
|
||||
subplot := 2
|
||||
seriestype := :scatter
|
||||
palette := palette
|
||||
color_palette := cp
|
||||
marker := (:circle, :diamond, :star5, :square)[j]
|
||||
randn(10), randn(10)
|
||||
end
|
||||
@@ -126,40 +96,43 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
@series begin
|
||||
subplot := 3
|
||||
seriestype := :histogram
|
||||
palette := palette
|
||||
color_palette := cp
|
||||
randn(1000) .+ (0:2:4)'
|
||||
end
|
||||
|
||||
f(r) = sin(r) / r
|
||||
_norm(x, y) = norm([x, y])
|
||||
x = y = linspace(-3π, 3π, 30)
|
||||
x = y = range(-3π, stop = 3π, length = 30)
|
||||
z = f.(_norm.(x, y'))
|
||||
wi = 2:3:30
|
||||
|
||||
@series begin
|
||||
subplot := 4
|
||||
seriestype := :heatmap
|
||||
seriescolor := gradient
|
||||
ticks := -5:5:5
|
||||
seriescolor := colorgradient
|
||||
xticks := (-2π:2π:2π, string.(-2:2:2, "π"))
|
||||
yticks := (-2π:2π:2π, string.(-2:2:2, "π"))
|
||||
x, y, z
|
||||
end
|
||||
|
||||
@series begin
|
||||
subplot := 5
|
||||
seriestype := :surface
|
||||
seriescolor := gradient
|
||||
seriescolor := colorgradient
|
||||
xticks := (-2π:2π:2π, string.(-2:2:2, "π"))
|
||||
yticks := (-2π:2π:2π, string.(-2:2:2, "π"))
|
||||
x, y, z
|
||||
end
|
||||
|
||||
n = 100
|
||||
ts = linspace(0, 10π, n)
|
||||
x = ts .* cos.(ts)
|
||||
ts = range(0, stop = 10π, length = n)
|
||||
x = (0.1ts) .* cos.(ts)
|
||||
y = (0.1ts) .* sin.(ts)
|
||||
z = 1:n
|
||||
|
||||
@series begin
|
||||
subplot := 6
|
||||
seriescolor := gradient
|
||||
seriescolor := colorgradient
|
||||
linewidth := 3
|
||||
line_z := z
|
||||
x, y, z
|
||||
|
||||
+12
-12
@@ -5,8 +5,10 @@
|
||||
const AVec = AbstractVector
|
||||
const AMat = AbstractMatrix
|
||||
const KW = Dict{Symbol,Any}
|
||||
const AKW = AbstractDict{Symbol,Any}
|
||||
const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString}
|
||||
|
||||
struct PlotsDisplay <: Display end
|
||||
struct PlotsDisplay <: AbstractDisplay end
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
@@ -16,15 +18,14 @@ end
|
||||
wrap(obj::T) where {T} = InputWrapper{T}(obj)
|
||||
Base.isempty(wrapper::InputWrapper) = false
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
mutable struct Series
|
||||
d::KW
|
||||
plotattributes::DefaultsDict
|
||||
end
|
||||
|
||||
attr(series::Series, k::Symbol) = series.d[k]
|
||||
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
|
||||
attr(series::Series, k::Symbol) = series.plotattributes[k]
|
||||
attr!(series::Series, v, k::Symbol) = (series.plotattributes[k] = v)
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
@@ -35,7 +36,7 @@ mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
|
||||
minpad::Tuple # leftpad, toppad, rightpad, bottompad
|
||||
bbox::BoundingBox # the canvas area which is available to this subplot
|
||||
plotarea::BoundingBox # the part where the data goes
|
||||
attr::KW # args specific to this subplot
|
||||
attr::DefaultsDict # args specific to this subplot
|
||||
o # can store backend-specific data... like a pyplot ax
|
||||
plt # the enclosing Plot object (can't give it a type because of no forward declarations)
|
||||
end
|
||||
@@ -47,7 +48,7 @@ Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
|
||||
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
|
||||
mutable struct Axis
|
||||
sps::Vector{Subplot}
|
||||
d::KW
|
||||
plotattributes::DefaultsDict
|
||||
end
|
||||
|
||||
mutable struct Extrema
|
||||
@@ -66,8 +67,7 @@ const SubplotMap = Dict{Any, Subplot}
|
||||
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||
backend::T # the backend type
|
||||
n::Int # number of series
|
||||
attr::KW # arguments for the whole plot
|
||||
user_attr::KW # raw arg inputs (after aliases). these are used as the input dict in `_plot!`
|
||||
attr::DefaultsDict # arguments for the whole plot
|
||||
series_list::Vector{Series} # arguments for each series
|
||||
o # the backend's plot object
|
||||
subplots::Vector{Subplot}
|
||||
@@ -78,7 +78,7 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||
end
|
||||
|
||||
function Plot()
|
||||
Plot(backend(), 0, KW(), KW(), Series[], nothing,
|
||||
Plot(backend(), 0, DefaultsDict(KW(), _plot_defaults), Series[], nothing,
|
||||
Subplot[], SubplotMap(), EmptyLayout(),
|
||||
Subplot[], false)
|
||||
end
|
||||
@@ -87,7 +87,7 @@ end
|
||||
|
||||
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
|
||||
Base.length(plt::Plot) = length(plt.subplots)
|
||||
Base.endof(plt::Plot) = length(plt)
|
||||
Base.lastindex(plt::Plot) = length(plt)
|
||||
|
||||
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
|
||||
Base.size(plt::Plot) = size(plt.layout)
|
||||
@@ -98,6 +98,6 @@ Base.ndims(plt::Plot) = 2
|
||||
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
|
||||
|
||||
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
|
||||
Base.endof(sp::Subplot) = length(series_list(sp))
|
||||
Base.lastindex(sp::Subplot) = length(series_list(sp))
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
+583
-629
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,9 @@
|
||||
|
||||
# [ADD BACKEND WEBSITE]
|
||||
|
||||
function _initialize_backend(::[PkgName]Backend; kw...)
|
||||
@eval begin
|
||||
import [PkgName]
|
||||
export [PkgName]
|
||||
# todo: other initialization that needs to be eval-ed
|
||||
end
|
||||
# todo: other initialization
|
||||
end
|
||||
import [PkgName]
|
||||
export [PkgName]
|
||||
push!(_initialized_backends, [pgkname]::Symbol)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -54,7 +49,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
|
||||
function _update_plot_object(plt::Plot{[PkgName]Backend})
|
||||
end
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
reference_images
|
||||
@@ -1,8 +0,0 @@
|
||||
StatPlots
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
GR 0.31.0
|
||||
RDatasets
|
||||
VisualRegressionTests
|
||||
UnicodePlots
|
||||
+47
-80
@@ -1,101 +1,68 @@
|
||||
import Plots._current_plots_version
|
||||
|
||||
using VisualRegressionTests
|
||||
# using ExamplePlots
|
||||
|
||||
import DataFrames, RDatasets
|
||||
|
||||
# don't let pyplot use a gui... it'll crash
|
||||
# note: Agg will set gui -> :none in PyPlot
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
try
|
||||
@eval import PyPlot
|
||||
info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
|
||||
# replace `f(args...)` with `f(rng, args...)` for `f ∈ (rand, randn)`
|
||||
function replace_rand!(ex) end
|
||||
function replace_rand!(ex::Expr)
|
||||
for arg in ex.args
|
||||
replace_rand!(arg)
|
||||
end
|
||||
if ex.head === :call && ex.args[1] ∈ (:rand, :randn)
|
||||
pushfirst!(ex.args, ex.args[1])
|
||||
ex.args[2] = :rng
|
||||
end
|
||||
end
|
||||
function fix_rand!(ex)
|
||||
replace_rand!(ex)
|
||||
pushfirst!(ex.args[1].args, :(rng = StableRNG(1234)))
|
||||
end
|
||||
|
||||
|
||||
using Plots
|
||||
using StatPlots
|
||||
using Base.Test
|
||||
|
||||
default(size=(500,300))
|
||||
|
||||
|
||||
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
|
||||
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
|
||||
|
||||
const _current_plots_version = v"0.17.4"
|
||||
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
function image_comparison_tests(
|
||||
pkg::Symbol,
|
||||
idx::Int;
|
||||
debug = false,
|
||||
popup = !is_ci(),
|
||||
sigma = [1, 1],
|
||||
tol = 1e-2,
|
||||
)
|
||||
Plots._debugMode.on = debug
|
||||
example = Plots._examples[idx]
|
||||
info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
Plots.theme(:default)
|
||||
@info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
backend(pkg)
|
||||
backend()
|
||||
default(size = (500, 300))
|
||||
|
||||
# ensure consistent results
|
||||
srand(1234)
|
||||
|
||||
# reference image directory setup
|
||||
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
|
||||
refdir = Pkg.dir("PlotReferenceImages", "Plots", string(pkg))
|
||||
fn = "ref$idx.png"
|
||||
|
||||
# firgure out version info
|
||||
vns = filter(x->x[1] != '.', readdir(refdir))
|
||||
versions = sort(VersionNumber.(vns), rev = true)
|
||||
versions = filter(v -> v <= _current_plots_version, versions)
|
||||
# @show refdir fn versions
|
||||
|
||||
newdir = joinpath(refdir, string(_current_plots_version))
|
||||
newfn = joinpath(newdir, fn)
|
||||
|
||||
# figure out which reference file we should compare to, by finding the highest versioned file
|
||||
reffn = nothing
|
||||
for v in versions
|
||||
tmpfn = joinpath(refdir, string(v), fn)
|
||||
if isfile(tmpfn)
|
||||
reffn = tmpfn
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# now we have the fn (if any)... do the comparison
|
||||
# @show reffn
|
||||
if reffn == nothing
|
||||
reffn = newfn
|
||||
end
|
||||
# @show reffn
|
||||
# return
|
||||
reffn = reference_file(pkg, idx, _current_plots_version)
|
||||
newfn = joinpath(reference_path(pkg, _current_plots_version), fn)
|
||||
|
||||
# test function
|
||||
func = (fn, idx) -> begin
|
||||
map(eval, example.exprs)
|
||||
expr = Expr(:block)
|
||||
append!(expr.args, example.exprs)
|
||||
fix_rand!(expr)
|
||||
eval(expr)
|
||||
png(fn)
|
||||
end
|
||||
|
||||
# try
|
||||
# run(`mkdir -p $newdir`)
|
||||
# catch err
|
||||
# display(err)
|
||||
# end
|
||||
# # reffn = joinpath(refdir, "ref$idx.png")
|
||||
|
||||
# the test
|
||||
vtest = VisualTest(func, reffn, idx)
|
||||
test_images(vtest, popup=popup, sigma=sigma, eps=eps, newfn = newfn)
|
||||
test_images(vtest, popup = popup, sigma = sigma, tol = tol, newfn = newfn)
|
||||
end
|
||||
|
||||
function image_comparison_facts(pkg::Symbol;
|
||||
skip = [], # skip these examples (int index)
|
||||
only = nothing, # limit to these examples (int index)
|
||||
debug = false, # print debug information?
|
||||
sigma = [1,1], # number of pixels to "blur"
|
||||
eps = 1e-2) # acceptable error (percent)
|
||||
for i in 1:length(Plots._examples)
|
||||
i in skip && continue
|
||||
if only == nothing || i in only
|
||||
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
|
||||
function image_comparison_facts(
|
||||
pkg::Symbol;
|
||||
skip = [], # skip these examples (int index)
|
||||
only = nothing, # limit to these examples (int index)
|
||||
debug = false, # print debug information?
|
||||
sigma = [1, 1], # number of pixels to "blur"
|
||||
tol = 1e-2,
|
||||
) # acceptable error (percent)
|
||||
for i = 1:length(Plots._examples)
|
||||
i in skip && continue
|
||||
if only === nothing || i in only
|
||||
@test image_comparison_tests(pkg, i, debug = debug, sigma = sigma, tol = tol) |>
|
||||
success == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
using Plots, Test, Dates
|
||||
|
||||
@testset "Limits" begin
|
||||
y=[1.0*i*i for i in 1:10]
|
||||
x=[Date(2019,11,i) for i in 1:10]
|
||||
|
||||
rx=[x[3],x[5]]
|
||||
|
||||
p = plot(x,y, widen = false)
|
||||
vspan!(p, rx, label="", alpha=0.2)
|
||||
|
||||
ref_ylims = (y[1], y[end])
|
||||
ref_xlims = (x[1].instant.periods.value, x[end].instant.periods.value)
|
||||
@test Plots.ylims(p) == ref_ylims
|
||||
@test Plots.xlims(p) == ref_xlims
|
||||
#@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI"))
|
||||
@static if haskey(ENV, "APPVEYOR")
|
||||
@info "Skipping display tests on AppVeyor"
|
||||
else
|
||||
@test isa(display(p), Nothing) == true
|
||||
closeall()
|
||||
end
|
||||
end # testset
|
||||
|
||||
@testset "Date xlims" begin
|
||||
y=[1.0*i*i for i in 1:10]
|
||||
x=[Date(2019,11,i) for i in 1:10]
|
||||
span = (Date(2019,10,31), Date(2019,11,11))
|
||||
|
||||
ref_xlims = map(date->date.instant.periods.value, span)
|
||||
|
||||
p = plot(x,y, xlims=span, widen = false)
|
||||
|
||||
@test Plots.xlims(p) == ref_xlims
|
||||
#@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI"))
|
||||
@static if haskey(ENV, "APPVEYOR")
|
||||
@info "Skipping display tests on AppVeyor"
|
||||
else
|
||||
@test isa(display(p), Nothing) == true
|
||||
closeall()
|
||||
end
|
||||
end # testset
|
||||
|
||||
@testset "DateTime xlims" begin
|
||||
y=[1.0*i*i for i in 1:10]
|
||||
x=[DateTime(2019,11,i,11) for i in 1:10]
|
||||
span = (DateTime(2019,10,31,11,59,59), DateTime(2019,11,11,12,01,15))
|
||||
|
||||
ref_xlims = map(date->date.instant.periods.value, span)
|
||||
|
||||
p = plot(x,y, xlims=span, widen = false)
|
||||
@test Plots.xlims(p) == ref_xlims
|
||||
#@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI"))
|
||||
@static if haskey(ENV, "APPVEYOR")
|
||||
@info "Skipping display tests on AppVeyor"
|
||||
else
|
||||
@test isa(display(p), Nothing) == true
|
||||
closeall()
|
||||
end
|
||||
end # testset
|
||||
+192
-136
@@ -1,120 +1,156 @@
|
||||
module PlotsTests
|
||||
using Plots: guidefont, series_annotations
|
||||
import ImageMagick
|
||||
using VisualRegressionTests
|
||||
using Plots
|
||||
using Random
|
||||
using StableRNGs
|
||||
using Test
|
||||
using TestImages
|
||||
using FileIO
|
||||
using Gtk
|
||||
using LibGit2
|
||||
import GeometryBasics
|
||||
using Dates
|
||||
using RecipesBase
|
||||
|
||||
|
||||
@testset "Plotly standalone" begin
|
||||
@test_nowarn Plots._init_ijulia_plotting()
|
||||
@test Plots.plotly_local_file_path[] === nothing
|
||||
temp = Plots.use_local_dependencies[]
|
||||
withenv("PLOTS_HOST_DEPENDENCY_LOCAL" => true) do
|
||||
Plots.__init__()
|
||||
@test Plots.plotly_local_file_path[] isa String
|
||||
@test isfile(Plots.plotly_local_file_path[])
|
||||
@test Plots.use_local_dependencies[] = true
|
||||
@test_nowarn Plots._init_ijulia_plotting()
|
||||
end
|
||||
Plots.plotly_local_file_path[] = nothing
|
||||
Plots.use_local_dependencies[] = temp
|
||||
end # testset
|
||||
|
||||
include("test_defaults.jl")
|
||||
include("test_pipeline.jl")
|
||||
include("test_axes.jl")
|
||||
include("test_axis_letter.jl")
|
||||
include("test_components.jl")
|
||||
include("test_shorthands.jl")
|
||||
include("integration_dates.jl")
|
||||
include("test_recipes.jl")
|
||||
include("test_hdf5plots.jl")
|
||||
include("test_pgfplotsx.jl")
|
||||
|
||||
reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
|
||||
|
||||
function reference_file(backend, i, version)
|
||||
refdir = reference_dir("Plots", string(backend))
|
||||
fn = "ref$i.png"
|
||||
versions = sort(VersionNumber.(readdir(refdir)), rev=true)
|
||||
|
||||
reffn = joinpath(refdir, string(version), fn)
|
||||
for v in versions
|
||||
tmpfn = joinpath(refdir, string(v), fn)
|
||||
if isfile(tmpfn)
|
||||
reffn = tmpfn
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return reffn
|
||||
end
|
||||
|
||||
reference_path(backend, version) = reference_dir("Plots", string(backend), string(version))
|
||||
|
||||
if !isdir(reference_dir())
|
||||
mkpath(reference_dir())
|
||||
LibGit2.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git", reference_dir())
|
||||
end
|
||||
|
||||
include("imgcomp.jl")
|
||||
|
||||
# don't actually show the plots
|
||||
srand(1234)
|
||||
Random.seed!(1234)
|
||||
default(show=false, reuse=true)
|
||||
img_eps = isinteractive() ? 1e-2 : 10e-2
|
||||
is_ci() = get(ENV, "CI", "false") == "true"
|
||||
const IMG_TOL = VERSION < v"1.4" && Sys.iswindows() ? 1e-1 : is_ci() ? 1e-2 : 1e-3
|
||||
|
||||
@testset "GR" begin
|
||||
ENV["PLOTS_TEST"] = "true"
|
||||
ENV["GKSwstype"] = "100"
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
## Uncomment the following lines to update reference images for different backends
|
||||
|
||||
image_comparison_facts(:gr, eps=img_eps)
|
||||
end
|
||||
|
||||
|
||||
#@testset "PyPlot" begin
|
||||
# @test pyplot() == Plots.PyPlotBackend()
|
||||
# @test backend() == Plots.PyPlotBackend()
|
||||
#
|
||||
# image_comparison_facts(:pyplot, eps=img_eps)
|
||||
#end
|
||||
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
# lets just make sure it runs without error
|
||||
@test isa(plot(rand(10)), Plots.Plot) == true
|
||||
end
|
||||
|
||||
# The plotlyjs testimages return a connection error on travis:
|
||||
# connect: connection refused (ECONNREFUSED)
|
||||
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# if is_linux() && isinteractive()
|
||||
# image_comparison_facts(:plotlyjs,
|
||||
# skip=[
|
||||
# 2, # animation (skipped for speed)
|
||||
# 27, # (polar plots) takes very long / not working
|
||||
# 31, # animation (skipped for speed)
|
||||
# ],
|
||||
# eps=img_eps)
|
||||
# end
|
||||
# @testset "GR" begin
|
||||
# image_comparison_facts(:gr, tol=IMG_TOL, skip = Plots._backend_skips[:gr])
|
||||
# end
|
||||
|
||||
|
||||
# InspectDR returns that error on travis:
|
||||
# ERROR: LoadError: InitError: Cannot open display:
|
||||
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
|
||||
|
||||
# @testset "InspectDR" begin
|
||||
# @test inspectdr() == Plots.InspectDRBackend()
|
||||
# @test backend() == Plots.InspectDRBackend()
|
||||
#
|
||||
# image_comparison_facts(:inspectdr,
|
||||
# skip=[
|
||||
# 2, # animation
|
||||
# 6, # heatmap not defined
|
||||
# 10, # heatmap not defined
|
||||
# 22, # contour not defined
|
||||
# 23, # pie not defined
|
||||
# 27, # polar plot not working
|
||||
# 28, # heatmap not defined
|
||||
# 31, # animation
|
||||
# ],
|
||||
# eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# plotly()
|
||||
# @testset "Plotly" begin
|
||||
# @test plotly() == Plots.PlotlyBackend()
|
||||
# @test backend() == Plots.PlotlyBackend()
|
||||
# image_comparison_facts(:plotly, tol=IMG_TOL, skip = Plots._backend_skips[:plotlyjs])
|
||||
# end
|
||||
#
|
||||
# # # until png generation is reliable on OSX, just test on linux
|
||||
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
|
||||
# pyplot()
|
||||
# @testset "PyPlot" begin
|
||||
# image_comparison_facts(:pyplot, tol=IMG_TOL, skip = Plots._backend_skips[:pyplot])
|
||||
# end
|
||||
#
|
||||
# pgfplotsx()
|
||||
# @testset "PGFPlotsX" begin
|
||||
# image_comparison_facts(:pgfplotsx, tol=IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
|
||||
# end
|
||||
|
||||
# 10 Histogram2D
|
||||
|
||||
# @testset "Immerse" begin
|
||||
# @test immerse() == Plots.ImmerseBackend()
|
||||
# @test backend() == Plots.ImmerseBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Gadfly
|
||||
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
|
||||
# end
|
||||
##
|
||||
|
||||
@testset "Backends" begin
|
||||
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Plotly
|
||||
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
|
||||
# end
|
||||
@testset "GR" begin
|
||||
ENV["PLOTS_TEST"] = "true"
|
||||
ENV["GKSwstype"] = "100"
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
@static if haskey(ENV, "APPVEYOR")
|
||||
@info "Skipping GR image comparison tests on AppVeyor"
|
||||
else
|
||||
image_comparison_facts(:gr, tol=IMG_TOL, skip=Plots._backend_skips[:gr])
|
||||
end
|
||||
end
|
||||
|
||||
# @testset "Gadfly" begin
|
||||
# @test gadfly() == Plots.GadflyBackend()
|
||||
# @test backend() == Plots.GadflyBackend()
|
||||
#
|
||||
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
|
||||
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
|
||||
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
|
||||
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
|
||||
#
|
||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
|
||||
# end
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
# lets just make sure it runs without error
|
||||
p = plot(rand(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = bar(randn(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = plot([1, 2], [3, 4])
|
||||
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
|
||||
hline!(p, [3.1])
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
|
||||
hline!(p, [3.1])
|
||||
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
|
||||
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
|
||||
hline!(p, [3.1])
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
end
|
||||
|
||||
@testset "PlotlyJS" begin
|
||||
@test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
@test backend() == Plots.PlotlyJSBackend()
|
||||
|
||||
p = plot(rand(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test_broken isa(display(p), Nothing) == true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@testset "Axes" begin
|
||||
p = plot()
|
||||
@@ -122,55 +158,75 @@ end
|
||||
@test typeof(axis) == Plots.Axis
|
||||
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
|
||||
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5,1.5)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5, 1.5)
|
||||
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
|
||||
Plots.discrete_value!(axis, ["x$i" for i=1:5])
|
||||
Plots.discrete_value!(axis, ["x$i" for i=0:2])
|
||||
Plots.discrete_value!(axis, ["x$i" for i = 1:5])
|
||||
Plots.discrete_value!(axis, ["x$i" for i = 0:2])
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
|
||||
end
|
||||
|
||||
@testset "NoFail" begin
|
||||
histogram([1, 0, 0, 0, 0, 0])
|
||||
#ensure backend with tested display
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
@testset "Plot" begin
|
||||
plots = [histogram([1, 0, 0, 0, 0, 0]),
|
||||
plot([missing]),
|
||||
plot([missing, missing]),
|
||||
plot(fill(missing, 10)),
|
||||
plot([missing; 1:4]),
|
||||
plot([fill(missing, 10); 1:4]),
|
||||
plot([1 1; 1 missing]),
|
||||
plot(["a" "b"; missing "d"], [1 2; 3 4])]
|
||||
for plt in plots
|
||||
display(plt)
|
||||
end
|
||||
@test_nowarn plot(x -> x^2, 0, 2)
|
||||
end
|
||||
|
||||
@testset "Bar" begin
|
||||
p = bar([3,2,1], [1,2,3]);
|
||||
@test isa(p, Plots.Plot)
|
||||
@test isa(display(p), Nothing) == true
|
||||
end
|
||||
end
|
||||
|
||||
# tests for preprocessing recipes
|
||||
|
||||
# @testset "recipes" begin
|
||||
@testset "EmptyAnim" begin
|
||||
anim = @animate for i in []
|
||||
end
|
||||
|
||||
# user recipe
|
||||
@test_throws ArgumentError gif(anim)
|
||||
end
|
||||
|
||||
# type T end
|
||||
# @recipe function f(::T)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# bg := :yellow
|
||||
# rand(10)
|
||||
# end
|
||||
# plot(T())
|
||||
@testset "NaN-separated Segments" begin
|
||||
segments(args...) = collect(iter_segments(args...))
|
||||
|
||||
# plot recipe
|
||||
nan10 = fill(NaN, 10)
|
||||
@test segments(11:20) == [1:10]
|
||||
@test segments([NaN]) == []
|
||||
@test segments(nan10) == []
|
||||
@test segments([nan10; 1:5]) == [11:15]
|
||||
@test segments([1:5;nan10]) == [1:5]
|
||||
@test segments([nan10; 1:5; nan10; 1:5; nan10]) == [11:15, 26:30]
|
||||
@test segments([NaN; 1], 1:10) == [2:2, 4:4, 6:6, 8:8, 10:10]
|
||||
@test segments([nan10; 1:15], [1:15; nan10]) == [11:15]
|
||||
end
|
||||
|
||||
# @recipe function f(::Type{Val{:hiplt}},plt::Plot)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# t := :path
|
||||
# bg:=:green
|
||||
# ()
|
||||
# end
|
||||
# plot(rand(10),t=:hiplt)
|
||||
|
||||
# series recipe
|
||||
|
||||
# @recipe function f(::Type{Val{:hi}},x,y,z)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# t := :path
|
||||
# ()
|
||||
# end
|
||||
# plot(rand(10),t=:hiplt)
|
||||
|
||||
# end
|
||||
|
||||
|
||||
end # module
|
||||
@testset "Utils" begin
|
||||
zipped = ([(1, 2)], [("a", "b")], [(1, "a"),(2, "b")],
|
||||
[(1, 2),(3, 4)], [(1, 2, 3),(3, 4, 5)], [(1, 2, 3, 4),(3, 4, 5, 6)],
|
||||
[(1, 2.0),(missing, missing)], [(1, missing),(missing, "a")],
|
||||
[(missing, missing)], [(missing, missing, missing),("a", "b", "c")])
|
||||
for z in zipped
|
||||
@test isequal(collect(zip(Plots.unzip(z)...)), z)
|
||||
@test isequal(collect(zip(Plots.unzip(GeometryBasics.Point.(z))...)), z)
|
||||
end
|
||||
op1 = Plots.process_clims((1.0, 2.0))
|
||||
op2 = Plots.process_clims((1, 2.0))
|
||||
data = randn(100, 100)
|
||||
@test op1(data) == op2(data)
|
||||
@test Plots.process_clims(nothing) == Plots.process_clims(missing) == Plots.process_clims(:auto)
|
||||
end
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import SnoopCompile
|
||||
|
||||
### Log the compiles
|
||||
# This only needs to be run once (to generate "/tmp/plots_compiles.csv")
|
||||
|
||||
# SnoopCompile.@snoop "/tmp/plots_compiles.csv" begin
|
||||
# include(joinpath(dirname(@__FILE__), "runtests.jl"))
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
### Parse the compiles and generate precompilation scripts
|
||||
# This can be run repeatedly to tweak the scripts
|
||||
|
||||
# IMPORTANT: we must have the module(s) defined for the parcelation
|
||||
# step, otherwise we will get no precompiles for the Plots module
|
||||
using Plots
|
||||
|
||||
data = SnoopCompile.read("/tmp/plots_compiles.csv")
|
||||
|
||||
# The Plots tests are run inside a module PlotsTest, so all
|
||||
# the precompiles get credited to PlotsTest. Credit them to Plots instead.
|
||||
subst = Dict("PlotsTests"=>"Plots")
|
||||
|
||||
# Blacklist helps fix problems:
|
||||
# - MIME uses type-parameters with symbols like :image/png, which is
|
||||
# not parseable
|
||||
blacklist = ["MIME"]
|
||||
|
||||
# Use these two lines if you want to create precompile functions for
|
||||
# individual packages
|
||||
pc, discards = SnoopCompile.parcel(data[end:-1:1,2], subst=subst, blacklist=blacklist)
|
||||
SnoopCompile.write("/tmp/precompile", pc)
|
||||
|
||||
pdir = joinpath(dirname(@__FILE__), "..")
|
||||
run(`cp /tmp/precompile/precompile_Plots.jl $pdir/src/precompile.jl`)
|
||||
@@ -0,0 +1,65 @@
|
||||
using Plots, Test
|
||||
|
||||
@testset "Showaxis" begin
|
||||
for value in Plots._allShowaxisArgs
|
||||
@test plot(1:5, showaxis = value)[1][:yaxis][:showaxis] isa Bool
|
||||
end
|
||||
@test plot(1:5, showaxis = :y)[1][:yaxis][:showaxis] == true
|
||||
@test plot(1:5, showaxis = :y)[1][:xaxis][:showaxis] == false
|
||||
end
|
||||
|
||||
@testset "Magic axis" begin
|
||||
@test plot(1, axis=nothing)[1][:xaxis][:ticks] == []
|
||||
@test plot(1, axis=nothing)[1][:yaxis][:ticks] == []
|
||||
end # testset
|
||||
|
||||
@testset "Categorical ticks" begin
|
||||
p1 = plot('A':'M', 1:13)
|
||||
p2 = plot('A':'Z', 1:26)
|
||||
p3 = plot('A':'Z', 1:26, ticks = :all)
|
||||
@test Plots.get_ticks(p1[1], p1[1][:xaxis])[2] == string.('A':'M')
|
||||
@test Plots.get_ticks(p2[1], p2[1][:xaxis])[2] == string.('C':3:'Z')
|
||||
@test Plots.get_ticks(p3[1], p3[1][:xaxis])[2] == string.('A':'Z')
|
||||
end
|
||||
|
||||
@testset "Ticks getter functions" begin
|
||||
ticks1 = ([1,2,3], ("a","b","c"))
|
||||
ticks2 = ([4,5], ("e","f"))
|
||||
p1 = plot(1:5, 1:5, 1:5, xticks=ticks1, yticks=ticks1, zticks=ticks1)
|
||||
p2 = plot(1:5, 1:5, 1:5, xticks=ticks2, yticks=ticks2, zticks=ticks2)
|
||||
p = plot(p1, p2)
|
||||
@test xticks(p) == yticks(p) == zticks(p) == [ticks1, ticks2]
|
||||
@test xticks(p[1]) == yticks(p[1]) == zticks(p[1]) == ticks1
|
||||
end
|
||||
|
||||
@testset "Axis limits" begin
|
||||
pl = plot(1:5, xlims=:symmetric, widen = false)
|
||||
@test Plots.xlims(pl) == (-5, 5)
|
||||
|
||||
pl = plot(1:3)
|
||||
@test Plots.xlims(pl) == Plots.widen(1,3)
|
||||
|
||||
pl = plot([1.05,2.0,2.95], ylims=:round)
|
||||
@test Plots.ylims(pl) == (1, 3)
|
||||
|
||||
pl = plot(1:3, xlims=(1,5))
|
||||
@test Plots.xlims(pl) == (1, 5)
|
||||
|
||||
pl = plot(1:3, xlims=(1,5), widen=true)
|
||||
@test Plots.xlims(pl) == Plots.widen(1, 5)
|
||||
end
|
||||
|
||||
@testset "3D Axis" begin
|
||||
ql = quiver([1, 2], [2, 1], [3, 4], quiver = ([1, -1], [0, 0], [1, -0.5]), arrow=true)
|
||||
@test ql[1][:projection] == "3d"
|
||||
end
|
||||
|
||||
@testset "twinx" begin
|
||||
pl = plot(1:10, margin = 2Plots.cm)
|
||||
twpl = twinx(pl)
|
||||
pl! = plot!(twinx(), -(1:10))
|
||||
@test twpl[:right_margin] == 2Plots.cm
|
||||
@test twpl[:left_margin] == 2Plots.cm
|
||||
@test twpl[:top_margin] == 2Plots.cm
|
||||
@test twpl[:bottom_margin] == 2Plots.cm
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
using Plots, Test
|
||||
|
||||
@testset "axis letter" begin
|
||||
using Plots, RecipesBase
|
||||
# a custom type for dispacthing the axis-letter-testing recipe
|
||||
struct MyType <: Number
|
||||
val::Float64
|
||||
end
|
||||
value(m::MyType) = m.val
|
||||
data = MyType.(sort(randn(20)))
|
||||
# A recipe that puts the axis letter in the title
|
||||
@recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:MyType}
|
||||
title --> string(plotattributes[:letter])
|
||||
value.(m)
|
||||
end
|
||||
@testset "$f (orientation = $o)" for f in [histogram, barhist, stephist, scatterhist], o in [:vertical, :horizontal]
|
||||
@test f(data, orientation=o).subplots[1].attr[:title] == (o == :vertical ? "x" : "y")
|
||||
end
|
||||
@testset "$f" for f in [hline, hspan]
|
||||
@test f(data).subplots[1].attr[:title] == "y"
|
||||
end
|
||||
@testset "$f" for f in [vline, vspan]
|
||||
@test f(data).subplots[1].attr[:title] == "x"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,151 @@
|
||||
using Plots, Test
|
||||
|
||||
@testset "Shapes" begin
|
||||
@testset "Type" begin
|
||||
square = Shape([(0, 0.0), (1, 0.0), (1, 1.0), (0, 1.0)])
|
||||
@test isa(square, Shape{Int64,Float64})
|
||||
@test coords(square) isa Tuple{Vector{S},Vector{T}} where {T,S}
|
||||
end
|
||||
|
||||
@testset "Copy" begin
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
square2 = Shape(square)
|
||||
@test square2.x == square.x
|
||||
@test square2.y == square.y
|
||||
end
|
||||
|
||||
@testset "Center" begin
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
@test Plots.center(square) == (0.5, 0.5)
|
||||
end
|
||||
|
||||
@testset "Translate" begin
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
squareUp = Shape([(0, 1), (1, 1), (1, 2), (0, 2)])
|
||||
squareUpRight = Shape([(1, 1), (2, 1), (2, 2), (1, 2)])
|
||||
|
||||
@test Plots.translate(square, 0, 1).x == squareUp.x
|
||||
@test Plots.translate(square, 0, 1).y == squareUp.y
|
||||
|
||||
@test Plots.center(translate!(square, 1)) == (1.5, 1.5)
|
||||
end
|
||||
|
||||
@testset "Rotate" begin
|
||||
# 2 radians rotation matrix
|
||||
R2 = [cos(2) sin(2); -sin(2) cos(2)]
|
||||
coords = [0 0; 1 0; 1 1; 0 1]'
|
||||
coordsRotated2 = R2 * (coords .- 0.5) .+ 0.5
|
||||
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
|
||||
# make a new, rotated square
|
||||
square2 = Plots.rotate(square, -2)
|
||||
@test square2.x ≈ coordsRotated2[1, :]
|
||||
@test square2.y ≈ coordsRotated2[2, :]
|
||||
|
||||
# unrotate the new square in place
|
||||
rotate!(square2, 2)
|
||||
@test square2.x ≈ coords[1, :]
|
||||
@test square2.y ≈ coords[2, :]
|
||||
end
|
||||
|
||||
@testset "Plot" begin
|
||||
ang = range(0, 2π, length = 60)
|
||||
ellipse(x, y, w, h) = Shape(w * sin.(ang) .+ x, h * cos.(ang) .+ y)
|
||||
myshapes = [ellipse(x, rand(), rand(), rand()) for x = 1:4]
|
||||
@test coords(myshapes) isa Tuple{Vector{Vector{S}},Vector{Vector{T}}} where {T,S}
|
||||
local p
|
||||
@test_nowarn p = plot(myshapes)
|
||||
@test p[1][1][:seriestype] == :shape
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Brush" begin
|
||||
@testset "Colors" begin
|
||||
baseline = brush(1, RGB(0, 0, 0))
|
||||
@test brush(:black) == baseline
|
||||
@test brush("black") == baseline
|
||||
end
|
||||
@testset "Weight" begin
|
||||
@test brush(10).size == 10
|
||||
@test brush(0.1).size == 1
|
||||
end
|
||||
@testset "Alpha" begin
|
||||
@test brush(0.4).alpha == 0.4
|
||||
@test brush(20).alpha == nothing
|
||||
end
|
||||
@testset "Bad Argument" begin
|
||||
# using test_logs because test_warn seems to not work anymore
|
||||
@test_logs (:warn, "Unused brush arg: nothing (Nothing)") begin
|
||||
brush(nothing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Fonts" begin
|
||||
@testset "Scaling" begin
|
||||
sizesToCheck = [
|
||||
:titlefontsize,
|
||||
:legendfontsize,
|
||||
:legendtitlefontsize,
|
||||
:xtickfontsize,
|
||||
:ytickfontsize,
|
||||
:ztickfontsize,
|
||||
:xguidefontsize,
|
||||
:yguidefontsize,
|
||||
:zguidefontsize,
|
||||
]
|
||||
# get inital font sizes
|
||||
initialSizes = [Plots.default(s) for s in sizesToCheck]
|
||||
|
||||
#scale up font sizes
|
||||
scalefontsizes(2)
|
||||
|
||||
# get inital font sizes
|
||||
doubledSizes = [Plots.default(s) for s in sizesToCheck]
|
||||
|
||||
@test doubledSizes == initialSizes * 2
|
||||
|
||||
# reset font sizes
|
||||
resetfontsizes()
|
||||
|
||||
finalSizes = [Plots.default(s) for s in sizesToCheck]
|
||||
|
||||
@test finalSizes == initialSizes
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Series Annotations" begin
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
@test_logs (:warn, "Unused SeriesAnnotations arg: triangle (Symbol)") begin
|
||||
p = plot(
|
||||
[1, 2, 3],
|
||||
series_annotations = (
|
||||
["a"],
|
||||
2, # pass a scale factor
|
||||
(1, 4), # pass two scale factors (overwrites first one)
|
||||
square, # pass a shape
|
||||
font(:courier), # pass an annotation font
|
||||
:triangle, # pass an incorrect argument
|
||||
),
|
||||
)
|
||||
sa = p.series_list[1].plotattributes[:series_annotations]
|
||||
@test sa.strs == ["a"]
|
||||
@test sa.font.family == "courier"
|
||||
@test sa.baseshape == square
|
||||
@test sa.scalefactor == (1, 4)
|
||||
end
|
||||
spl = scatter(
|
||||
4.53 .* [1/1 1/2 1/3 1/4 1/5],
|
||||
[0 0 0 0 0],
|
||||
layout = (5, 1),
|
||||
ylims = (-1.1, 1.1),
|
||||
xlims = (0, 5),
|
||||
series_annotations = permutedims([["1/1"],["1/2"],["1/3"],["1/4"],["1/5"]]),
|
||||
)
|
||||
@test spl.series_list[1].plotattributes[:series_annotations].strs == ["1/1"]
|
||||
@test spl.series_list[2].plotattributes[:series_annotations].strs == ["1/2"]
|
||||
@test spl.series_list[3].plotattributes[:series_annotations].strs == ["1/3"]
|
||||
@test spl.series_list[4].plotattributes[:series_annotations].strs == ["1/4"]
|
||||
@test spl.series_list[5].plotattributes[:series_annotations].strs == ["1/5"]
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
using Plots, Test
|
||||
|
||||
const PLOTS_DEFAULTS = Dict(:theme => :wong2, :fontfamily => :palantino)
|
||||
Plots.__init__()
|
||||
|
||||
@testset "Loading theme" begin
|
||||
pl = plot(1:5)
|
||||
@test pl[1][1][:seriescolor] == RGBA(colorant"black")
|
||||
@test guidefont(pl[1][:xaxis]).family == "palantino"
|
||||
end
|
||||
|
||||
empty!(PLOTS_DEFAULTS)
|
||||
Plots.__init__()
|
||||
@@ -0,0 +1,21 @@
|
||||
using Plots, HDF5
|
||||
|
||||
|
||||
@testset "HDF5_Plots" begin
|
||||
fname = "tmpplotsave.hdf5"
|
||||
hdf5()
|
||||
|
||||
x = 1:10
|
||||
psrc=plot(x, x.*x); #Create some plot
|
||||
Plots.hdf5plot_write(psrc, fname)
|
||||
|
||||
#Read back file:
|
||||
gr() #Choose some fast backend likely to work in test environment.
|
||||
pread = Plots.hdf5plot_read(fname)
|
||||
|
||||
#Make sure data made it through:
|
||||
@test psrc.subplots[1].series_list[1][:x] == pread.subplots[1].series_list[1][:x]
|
||||
@test psrc.subplots[1].series_list[1][:y] == pread.subplots[1].series_list[1][:y]
|
||||
|
||||
#display(pread) #Don't display. Regression env might not support
|
||||
end #testset
|
||||
@@ -0,0 +1,421 @@
|
||||
using Plots, Test
|
||||
pgfplotsx()
|
||||
|
||||
function create_plot(args...; kwargs...)
|
||||
pgfx_plot = plot(args...; kwargs...)
|
||||
return pgfx_plot, repr("application/x-tex", pgfx_plot)
|
||||
end
|
||||
|
||||
function create_plot!(args...; kwargs...)
|
||||
pgfx_plot = plot!(args...; kwargs...)
|
||||
return pgfx_plot, repr("application/x-tex", pgfx_plot)
|
||||
end
|
||||
|
||||
@testset "PGFPlotsX" begin
|
||||
pgfx_plot = plot(1:5)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
@test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument
|
||||
@test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing
|
||||
axis = Plots.pgfx_axes(pgfx_plot.o)[1]
|
||||
@test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 1
|
||||
@test !haskey(axis.contents[1].options.dict, "fill")
|
||||
|
||||
@testset "Legends" begin
|
||||
legends_plot = plot(rand(5, 2), lab = ["1" ""])
|
||||
scatter!(legends_plot, rand(5))
|
||||
Plots._update_plot_object(legends_plot)
|
||||
axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents
|
||||
leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
|
||||
series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
|
||||
@test length(leg_entries) == 2
|
||||
@test !haskey(series[1].options.dict, "forget plot")
|
||||
@test haskey(series[2].options.dict, "forget plot")
|
||||
@test !haskey(series[3].options.dict, "forget plot")
|
||||
end # testset
|
||||
|
||||
@testset "3D docs example" begin
|
||||
n = 100
|
||||
ts = range(0, stop = 8π, length = n)
|
||||
x = ts .* map(cos, ts)
|
||||
y = (0.1ts) .* map(sin, ts)
|
||||
z = 1:n
|
||||
pl = plot(
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
zcolor = reverse(z),
|
||||
m = (10, 0.8, :blues, Plots.stroke(0)),
|
||||
leg = false,
|
||||
cbar = true,
|
||||
w = 5,
|
||||
)
|
||||
pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w = 10)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
if @test_nowarn(
|
||||
haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true
|
||||
)
|
||||
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
|
||||
end
|
||||
end # testset
|
||||
@testset "Color docs example" begin
|
||||
y = rand(100)
|
||||
plot(
|
||||
0:10:100,
|
||||
rand(11, 4),
|
||||
lab = "lines",
|
||||
w = 3,
|
||||
palette = :grays,
|
||||
fill = 0,
|
||||
α = 0.6,
|
||||
)
|
||||
pl = scatter!(
|
||||
y,
|
||||
zcolor = abs.(y .- 0.5),
|
||||
m = (:hot, 0.8, Plots.stroke(1, :green)),
|
||||
ms = 10 * abs.(y .- 0.5) .+ 4,
|
||||
lab = ["grad", "", "ient"],
|
||||
)
|
||||
Plots._update_plot_object(pl)
|
||||
axis = Plots.pgfx_axes(pl.o)[1]
|
||||
@test count(x -> x isa PGFPlotsX.LegendEntry, axis.contents) == 6
|
||||
@test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 108 # each marker is its own plot, fillranges create 2 plot-objects
|
||||
marker = axis.contents[15]
|
||||
@test marker isa PGFPlotsX.Plot
|
||||
@test marker.options["mark"] == "*"
|
||||
@test marker.options["mark options"]["color"] ==
|
||||
RGBA{Float64}(colorant"green", 0.8)
|
||||
@test marker.options["mark options"]["line width"] == 0.75 # 1px is 0.75pt
|
||||
end # testset
|
||||
@testset "Plot in pieces" begin
|
||||
pic = plot(rand(100) / 3, reg = true, fill = (0, :green))
|
||||
scatter!(pic, rand(100), markersize = 6, c = :orange)
|
||||
Plots._update_plot_object(pic)
|
||||
axis_contents = Plots.pgfx_axes(pic.o)[1].contents
|
||||
leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
|
||||
series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
|
||||
@test length(leg_entries) == 2
|
||||
@test length(series) == 4
|
||||
@test haskey(series[1].options.dict, "forget plot")
|
||||
@test !haskey(series[2].options.dict, "forget plot")
|
||||
@test haskey(series[3].options.dict, "forget plot")
|
||||
@test !haskey(series[4].options.dict, "forget plot")
|
||||
end # testset
|
||||
@testset "Marker types" begin
|
||||
markers = filter((m -> begin
|
||||
m in Plots.supported_markers()
|
||||
end), Plots._shape_keys)
|
||||
markers = reshape(markers, 1, length(markers))
|
||||
n = length(markers)
|
||||
x = (range(0, stop = 10, length = n + 2))[2:(end-1)]
|
||||
y = repeat(reshape(reverse(x), 1, :), n, 1)
|
||||
scatter(
|
||||
x,
|
||||
y,
|
||||
m = (8, :auto),
|
||||
lab = map(string, markers),
|
||||
bg = :linen,
|
||||
xlim = (0, 10),
|
||||
ylim = (0, 10),
|
||||
)
|
||||
end # testset
|
||||
@testset "Layout" begin
|
||||
plot(
|
||||
Plots.fakedata(100, 10),
|
||||
layout = 4,
|
||||
palette = [:grays :blues :hot :rainbow],
|
||||
bg_inside = [:orange :pink :darkblue :black],
|
||||
)
|
||||
end # testset
|
||||
@testset "Polar plots" begin
|
||||
Θ = range(0, stop = 1.5π, length = 100)
|
||||
r = abs.(0.1 * randn(100) + sin.(3Θ))
|
||||
plot(Θ, r, proj = :polar, m = 2)
|
||||
end # testset
|
||||
@testset "Drawing shapes" begin
|
||||
verts = [
|
||||
(-1.0, 1.0),
|
||||
(-1.28, 0.6),
|
||||
(-0.2, -1.4),
|
||||
(0.2, -1.4),
|
||||
(1.28, 0.6),
|
||||
(1.0, 1.0),
|
||||
(-1.0, 1.0),
|
||||
(-0.2, -0.6),
|
||||
(0.0, -0.2),
|
||||
(-0.4, 0.6),
|
||||
(1.28, 0.6),
|
||||
(0.2, -1.4),
|
||||
(-0.2, -1.4),
|
||||
(0.6, 0.2),
|
||||
(-0.2, 0.2),
|
||||
(0.0, -0.2),
|
||||
(0.2, 0.2),
|
||||
(-0.2, -0.6),
|
||||
]
|
||||
x = 0.1:0.2:0.9
|
||||
y = 0.7 * rand(5) .+ 0.15
|
||||
plot(
|
||||
x,
|
||||
y,
|
||||
line = (3, :dash, :lightblue),
|
||||
marker = (Shape(verts), 30, RGBA(0, 0, 0, 0.2)),
|
||||
bg = :pink,
|
||||
fg = :darkblue,
|
||||
xlim = (0, 1),
|
||||
ylim = (0, 1),
|
||||
leg = false,
|
||||
)
|
||||
end # testset
|
||||
@testset "Histogram 2D" begin
|
||||
histogram2d(randn(10000), randn(10000), nbins = 20)
|
||||
end # testset
|
||||
@testset "Heatmap-like" begin
|
||||
xs = [string("x", i) for i = 1:10]
|
||||
ys = [string("y", i) for i = 1:4]
|
||||
z = float((1:4) * reshape(1:10, 1, :))
|
||||
pgfx_plot = heatmap(xs, ys, z, aspect_ratio = 1)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
if @test_nowarn(
|
||||
haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true
|
||||
)
|
||||
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
|
||||
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1"
|
||||
end
|
||||
|
||||
pgfx_plot = wireframe(xs, ys, z, aspect_ratio = 1)
|
||||
# TODO: clims are wrong
|
||||
end # testset
|
||||
@testset "Contours" begin
|
||||
x = 1:0.5:20
|
||||
y = 1:0.5:10
|
||||
f(x, y) = begin
|
||||
(3x + y^2) * abs(sin(x) + cos(y))
|
||||
end
|
||||
X = repeat(reshape(x, 1, :), length(y), 1)
|
||||
Y = repeat(y, 1, length(x))
|
||||
Z = map(f, X, Y)
|
||||
p2 = contour(x, y, Z)
|
||||
p1 = contour(x, y, f, fill = true)
|
||||
plot(p1, p2)
|
||||
# TODO: colorbar for filled contours
|
||||
end # testset
|
||||
@testset "Varying colors" begin
|
||||
t = range(0, stop = 1, length = 100)
|
||||
θ = (6π) .* t
|
||||
x = t .* cos.(θ)
|
||||
y = t .* sin.(θ)
|
||||
p1 = plot(x, y, line_z = t, linewidth = 3, legend = false)
|
||||
p2 = scatter(
|
||||
x,
|
||||
y,
|
||||
marker_z = ((x, y) -> begin
|
||||
x + y
|
||||
end),
|
||||
color = :bwr,
|
||||
legend = false,
|
||||
)
|
||||
plot(p1, p2)
|
||||
end # testset
|
||||
@testset "Framestyles" begin
|
||||
scatter(
|
||||
fill(randn(10), 6),
|
||||
fill(randn(10), 6),
|
||||
framestyle = [:box :semi :origin :zerolines :grid :none],
|
||||
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
|
||||
color = permutedims(1:6),
|
||||
layout = 6,
|
||||
label = "",
|
||||
markerstrokewidth = 0,
|
||||
ticks = -2:2,
|
||||
)
|
||||
# TODO: support :semi
|
||||
end # testset
|
||||
@testset "Quiver" begin
|
||||
x = (-2pi):0.2:(2*pi)
|
||||
y = sin.(x)
|
||||
|
||||
u = ones(length(x))
|
||||
v = cos.(x)
|
||||
arrow_plot = plot(x, y, quiver = (u, v), arrow = true)
|
||||
# TODO: could adjust limits to fit arrows if too long, but how?
|
||||
# TODO: get latex available on CI
|
||||
# mktempdir() do path
|
||||
# @test_nowarn savefig(arrow_plot, path*"arrow.pdf")
|
||||
# end
|
||||
end # testset
|
||||
@testset "Annotations" begin
|
||||
y = rand(10)
|
||||
pgfx_plot = plot(
|
||||
y,
|
||||
annotations = (3, y[3], Plots.text("this is \\#3", :left)),
|
||||
leg = false,
|
||||
)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
|
||||
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
|
||||
@test length(nodes) == 1
|
||||
mktempdir() do path
|
||||
file_path = joinpath(path, "annotations.tex")
|
||||
@test_nowarn savefig(pgfx_plot, file_path)
|
||||
open(file_path) do io
|
||||
lines = readlines(io)
|
||||
@test count(s -> occursin("node", s), lines) == 1
|
||||
end
|
||||
end
|
||||
annotate!([
|
||||
(5, y[5], Plots.text("this is \\#5", 16, :red, :center)),
|
||||
(10, y[10], Plots.text("this is \\#10", :right, 20, "courier")),
|
||||
])
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
|
||||
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
|
||||
@test length(nodes) == 3
|
||||
mktempdir() do path
|
||||
file_path = joinpath(path, "annotations.tex")
|
||||
@test_nowarn savefig(pgfx_plot, file_path)
|
||||
open(file_path) do io
|
||||
lines = readlines(io)
|
||||
@test count(s -> occursin("node", s), lines) == 3
|
||||
end
|
||||
end
|
||||
annotation_plot = scatter!(
|
||||
range(2, stop = 8, length = 6),
|
||||
rand(6),
|
||||
marker = (50, 0.2, :orange),
|
||||
series_annotations = [
|
||||
"series",
|
||||
"annotations",
|
||||
"map",
|
||||
"to",
|
||||
"series",
|
||||
Plots.text("data", :green),
|
||||
],
|
||||
)
|
||||
Plots._update_plot_object(annotation_plot)
|
||||
axis_content = Plots.pgfx_axes(annotation_plot.o)[1].contents
|
||||
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
|
||||
@test length(nodes) == 9
|
||||
mktempdir() do path
|
||||
file_path = joinpath(path, "annotations.tex")
|
||||
@test_nowarn savefig(annotation_plot, file_path)
|
||||
open(file_path) do io
|
||||
lines = readlines(io)
|
||||
@test count(s -> occursin("node", s), lines) == 9
|
||||
end
|
||||
# test .tikz extension
|
||||
file_path = joinpath(path, "annotations.tikz")
|
||||
@test_nowarn savefig(annotation_plot, file_path)
|
||||
@test_nowarn open(file_path) do io
|
||||
end
|
||||
end
|
||||
end # testset
|
||||
@testset "Ribbon" begin
|
||||
aa = rand(10)
|
||||
bb = rand(10)
|
||||
cc = rand(10)
|
||||
conf = [aa - cc bb - cc]
|
||||
ribbon_plot =
|
||||
plot(collect(1:10), fill(1, 10), ribbon = (conf[:, 1], conf[:, 2]))
|
||||
Plots._update_plot_object(ribbon_plot)
|
||||
axis = Plots.pgfx_axes(ribbon_plot.o)[1]
|
||||
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
|
||||
@test length(plots) == 3
|
||||
@test haskey(plots[1].options.dict, "fill")
|
||||
@test haskey(plots[2].options.dict, "fill")
|
||||
@test !haskey(plots[3].options.dict, "fill")
|
||||
@test ribbon_plot.o !== nothing
|
||||
@test ribbon_plot.o.the_plot !== nothing
|
||||
end # testset
|
||||
@testset "Markers and Paths" begin
|
||||
pl = plot(
|
||||
5 .- ones(9),
|
||||
markershape = [:utriangle, :rect],
|
||||
markersize = 8,
|
||||
color = [:red, :black],
|
||||
)
|
||||
Plots._update_plot_object(pl)
|
||||
axis = Plots.pgfx_axes(pl.o)[1]
|
||||
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
|
||||
@test length(plots) == 9
|
||||
end # testset
|
||||
@testset "Groups and Subplots" begin
|
||||
group = rand(map((i->begin
|
||||
"group $(i)"
|
||||
end), 1:4), 100)
|
||||
pl = plot(rand(100), layout = @layout([a b; c]), group = group, linetype = [:bar :scatter :steppre], linecolor = :match)
|
||||
Plots._update_plot_object(pl)
|
||||
axis = Plots.pgfx_axes(pl.o)[1]
|
||||
legend_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis.contents)
|
||||
@test length(legend_entries) == 2
|
||||
end
|
||||
end # testset
|
||||
|
||||
@testset "Extra kwargs" begin
|
||||
pl = plot(1:5, test = "me")
|
||||
@test pl[1][1].plotattributes[:extra_kwargs][:test] == "me"
|
||||
pl = plot(1:5, test = "me", extra_kwargs = :subplot)
|
||||
@test pl[1].attr[:extra_kwargs][:test] == "me"
|
||||
pl = plot(1:5, test = "me", extra_kwargs = :plot)
|
||||
@test pl.attr[:extra_plot_kwargs][:test] == "me"
|
||||
pl = plot(
|
||||
1:5,
|
||||
extra_kwargs = Dict(
|
||||
:plot => Dict(:test => "me"),
|
||||
:series => Dict(:and => "me too"),
|
||||
),
|
||||
)
|
||||
@test pl.attr[:extra_plot_kwargs][:test] == "me"
|
||||
@test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too"
|
||||
pl = plot(
|
||||
plot(1:5, title = "Line"),
|
||||
scatter(
|
||||
1:5,
|
||||
title = "Scatter",
|
||||
extra_kwargs = Dict(:subplot => Dict("axis line shift" => "10pt")),
|
||||
),
|
||||
)
|
||||
Plots._update_plot_object(pl)
|
||||
axes = Plots.pgfx_axes(pl.o)
|
||||
@test !haskey(axes[1].options.dict, "axis line shift")
|
||||
@test haskey(axes[2].options.dict, "axis line shift")
|
||||
pl = plot(
|
||||
x -> x,
|
||||
-1:1;
|
||||
add = raw"\node at (0,0.5) {\huge hi};",
|
||||
extra_kwargs = :subplot,
|
||||
)
|
||||
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
|
||||
Plots._update_plot_object(pl)
|
||||
axes = Plots.pgfx_axes(pl.o)
|
||||
@test filter(x -> x isa String, axes[1].contents)[1] ==
|
||||
raw"\node at (0,0.5) {\huge hi};"
|
||||
plot!(pl)
|
||||
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
|
||||
Plots._update_plot_object(pl)
|
||||
axes = Plots.pgfx_axes(pl.o)
|
||||
@test filter(x -> x isa String, axes[1].contents)[1] ==
|
||||
raw"\node at (0,0.5) {\huge hi};"
|
||||
end # testset
|
||||
|
||||
@testset "Titlefonts" begin
|
||||
pl = plot(1:5, title = "Test me", titlefont = (2, :left))
|
||||
@test pl[1][:title] == "Test me"
|
||||
@test pl[1][:titlefontsize] == 2
|
||||
@test pl[1][:titlefonthalign] == :left
|
||||
Plots._update_plot_object(pl)
|
||||
ax_opt = Plots.pgfx_axes(pl.o)[1].options
|
||||
@test ax_opt["title"] == "Test me"
|
||||
@test(haskey(ax_opt.dict, "title style")) isa Test.Pass
|
||||
pl = plot(1:5, plot_title = "Test me", plot_titlefont = (2, :left))
|
||||
@test pl[:plot_title] == "Test me"
|
||||
@test pl[:plot_titlefontsize] == 2
|
||||
@test pl[:plot_titlefonthalign] == :left
|
||||
pl = heatmap(
|
||||
rand(3, 3),
|
||||
colorbar_title = "Test me",
|
||||
colorbar_titlefont = (12, :right),
|
||||
)
|
||||
@test pl[1][:colorbar_title] == "Test me"
|
||||
@test pl[1][:colorbar_titlefontsize] == 12
|
||||
@test pl[1][:colorbar_titlefonthalign] == :right
|
||||
end # testset
|
||||
@@ -0,0 +1,19 @@
|
||||
using Plots, Test
|
||||
using RecipesPipeline
|
||||
|
||||
@testset "plot" begin
|
||||
pl = plot(1:5)
|
||||
pl2 = plot(pl, tex_output_standalone = true)
|
||||
@test pl[:tex_output_standalone] == false
|
||||
@test pl2[:tex_output_standalone] == true
|
||||
plot!(pl, tex_output_standalone = true)
|
||||
@test pl[:tex_output_standalone] == true
|
||||
end
|
||||
|
||||
@testset "get_axis_limits" begin
|
||||
x = [.1, 5]
|
||||
p1 = plot(x, [5, .1], yscale=:log10)
|
||||
p2 = plot!(identity)
|
||||
@test all(RecipesPipeline.get_axis_limits(p1, :x) .== x)
|
||||
@test all(RecipesPipeline.get_axis_limits(p2, :x) .== x)
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
using Plots, Test
|
||||
using OffsetArrays
|
||||
|
||||
@testset "lens!" begin
|
||||
pl = plot(1:5)
|
||||
lens!(pl, [1,2], [1,2], inset = (1, bbox(0.0,0.0,0.2,0.2)), colorbar = false)
|
||||
@test length(pl.series_list) == 4
|
||||
@test pl[2][:colorbar] == :none
|
||||
end # testset
|
||||
|
||||
@testset "vline, vspan" begin
|
||||
vl = vline([1], widen = false)
|
||||
@test Plots.xlims(vl) == (1,2)
|
||||
@test Plots.ylims(vl) == (1,2)
|
||||
vl = vline([1], xlims=(0,2), widen = false)
|
||||
@test Plots.xlims(vl) == (0,2)
|
||||
vl = vline([1], ylims=(-3,5), widen = false)
|
||||
@test Plots.ylims(vl) == (-3,5)
|
||||
|
||||
vsp = vspan([1,3], widen = false)
|
||||
@test Plots.xlims(vsp) == (1,3)
|
||||
@test Plots.ylims(vsp) == (0,1) # TODO: might be problematic on log-scales
|
||||
vsp = vspan([1,3], xlims=(-2,5), widen = false)
|
||||
@test Plots.xlims(vsp) == (-2,5)
|
||||
vsp = vspan([1,3], ylims=(-2,5), widen = false)
|
||||
@test Plots.ylims(vsp) == (-2,5)
|
||||
end # testset
|
||||
|
||||
@testset "offset axes" begin
|
||||
tri = OffsetVector(vcat(1:5, 4:-1:1), 11:19)
|
||||
sticks = plot(tri, seriestype = :sticks)
|
||||
@test length(sticks) == 1
|
||||
end
|
||||
|
||||
@testset "framestyle axes" begin
|
||||
pl = plot(-1:1, -1:1, -1:1)
|
||||
sp = pl.subplots[1]
|
||||
defaultret = Plots.axis_drawing_info_3d(sp, :x)
|
||||
for letter in [:x, :y, :z]
|
||||
for fr in [:box :semi :origin :zerolines :grid :none]
|
||||
prevha = UInt64(0)
|
||||
push!(sp.attr, :framestyle => fr)
|
||||
ret = Plots.axis_drawing_info_3d(sp, letter)
|
||||
ha = hash(string(ret))
|
||||
@test ha != prevha
|
||||
prevha = ha
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,48 @@
|
||||
using Plots, Test
|
||||
|
||||
@testset "Shorthands" begin
|
||||
@testset "Set Lims" begin
|
||||
p = plot(rand(10))
|
||||
|
||||
xlims!((1,20))
|
||||
@test xlims(p) == (1,20)
|
||||
|
||||
ylims!((-1,1))
|
||||
@test ylims(p) == (-1,1)
|
||||
|
||||
zlims!((-1,1))
|
||||
@test zlims(p) == (-1,1)
|
||||
|
||||
xlims!(-1,11)
|
||||
@test xlims(p) == (-1,11)
|
||||
|
||||
ylims!((-10,10))
|
||||
@test ylims(p) == (-10,10)
|
||||
|
||||
zlims!((-10,10))
|
||||
@test zlims(p) == (-10,10)
|
||||
end
|
||||
|
||||
@testset "Set Ticks" begin
|
||||
p = plot([0,2,3,4,5,6,7,8,9,10])
|
||||
|
||||
xticks = 2:6
|
||||
xticks!(xticks)
|
||||
@test Plots.get_subplot(current(),1).attr[:xaxis][:ticks] == xticks
|
||||
|
||||
yticks = 0.2:0.1:0.7
|
||||
yticks!(yticks)
|
||||
@test Plots.get_subplot(current(),1).attr[:yaxis][:ticks] == yticks
|
||||
|
||||
xticks = [5,6,7.5]
|
||||
xlabels = ["a","b","c"]
|
||||
|
||||
xticks!(xticks, xlabels)
|
||||
@test Plots.get_subplot(current(),1).attr[:xaxis][:ticks] == (xticks, xlabels)
|
||||
|
||||
yticks = [.5,.6,.75]
|
||||
ylabels = ["z","y","x"]
|
||||
yticks!(yticks, ylabels)
|
||||
@test Plots.get_subplot(current(),1).attr[:yaxis][:ticks] == (yticks, ylabels)
|
||||
end
|
||||
end
|
||||
@@ -1,31 +0,0 @@
|
||||
Pkg.add("ImageMagick")
|
||||
Pkg.build("ImageMagick")
|
||||
|
||||
# Pkg.clone("GR")
|
||||
# Pkg.build("GR")
|
||||
|
||||
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
|
||||
|
||||
# Pkg.clone("https://github.com/JuliaStats/KernelDensity.jl.git")
|
||||
|
||||
Pkg.clone("StatPlots")
|
||||
# Pkg.checkout("PlotUtils")
|
||||
|
||||
# Pkg.clone("Blink")
|
||||
# Pkg.build("Blink")
|
||||
# import Blink
|
||||
# Blink.AtomShell.install()
|
||||
# Pkg.add("Rsvg")
|
||||
# Pkg.add("PlotlyJS")
|
||||
|
||||
# Pkg.checkout("RecipesBase")
|
||||
# Pkg.clone("VisualRegressionTests")
|
||||
|
||||
# need this to use Conda
|
||||
ENV["PYTHON"] = ""
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.build("PyPlot")
|
||||
|
||||
# Pkg.add("InspectDR")
|
||||
|
||||
Pkg.test("Plots"; coverage=false)
|
||||
Reference in New Issue
Block a user