├── .gitignore ├── LICENSE ├── README.md ├── data ├── Glasser_2016.32k.L.label.gii ├── MyelinMap_flat_vectors.L.func.gii ├── MyelinMap_inflated_vectors.L.func.gii ├── S1200.MyelinMap.L.func.gii ├── fs_LR.32k.L.flat.surf.gii ├── fs_LR.32k.L.inflated.surf.gii ├── geodesic_distance_flat_vectors.func.gii ├── geodesic_distance_inflated_vectors.func.gii ├── lh.aparc.annot ├── lh.cortex.label ├── lh.inflated ├── lh.sulc ├── lh.thickness └── v1_geodesic.func.gii ├── examples ├── alpha_colours.ipynb ├── arrows_map.ipynb ├── flat_map.ipynb ├── hcp_example.ipynb ├── plot_surface_with_parcellation.ipynb └── script_matplotlib.py ├── figs └── demo_plot.png ├── matplotlib_surface_plotting ├── __init__.py └── matplotlib_surface_plotting.py ├── setup.py └── test └── test-pip.py /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__/ 2 | *.egg-info/ 3 | dist/ 4 | build/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 kwagstyl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Matplotlib surface plotting 2 | 3 | Matplotlib 3D mesh plotter for plotting brain meshes 4 | ![plot](https://github.com/kwagstyl/matplotlib_surface_plotting/blob/main/figs/demo_plot.png?raw=true) 5 | 6 | pip install matplotlib-surface-plotting 7 | 8 | Run example: 9 | 10 | python scripts/script_matplotlib.py 11 | to create demo_plot.png using demo files 12 | 13 | 14 | Based on a matplotlib blogpost by Nicolas P. Rougier 15 | 16 | Contributors: M. Ripart, U. Popple, K. Wagstyl 17 | -------------------------------------------------------------------------------- /data/Glasser_2016.32k.L.label.gii: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | eJztnYu3XVV1xg8l0CQELaJWofKUgpZHkUQeVXxRKSjgAwqoRaQUwSJCgQo2gCFQoSLgI5SgtEGkVUHSAH9g7xk9azg7me8519r7xLvH+Ma9OWev7/t9a+97s8/aJzmnLRaLnRvasaETNnTshvZt6LrF/237N/T4hm7b0N4NnYb0DkLrvOF+WKcqOtmoBw06wqgtQPsFHaibpvLtAaDvIj3MiOqonZ/rvG32Wp/tcPv9eDgdH6rLOm6HQ491P6fWef7Xdd6X11nrxo2Z5869TnO8LqztNcKcWefOOGc++PpuTmwU19RsHNNUXPj1+ZQ8EstInjlwUGsnI19TWfKnzO7B8KAjuzKzaUQmXmvjMtsaVGVWE17ngqrMkbIeKMzgctq6Xg//Sm/s/wDSSN+sJ/Y+wunHeTYvzc/idYTitYXwwV6cxxajh7SWDkV5WMZRYy1jHibGSPu3MW2cZb8m7v4Btx9ec8f7UOvy0pq99px0T0OTdj+n6RRCf27UhwL6C6NOcOizG/pEUJcSetOhtxhltxHHL3IMK45ftJe3X49e8Nzx9pI6WbtZ+3wMyNsLdsPrvN4+rdPFQJFOHyPk6dM6UdfVni4XM8p2kfpwv7u410TvSHa5eEY9LF2kHloXrgPXI9pB6xHtIPFTHTL8Ugcvv8ZN8XPscIvwa+xQf+Vgb/wW7gi7lbfJw21ltnBD9l7MHl4Ps5XTw/qmk9XCfclKVazwGjfCSfFeglTJiDm9Ww9G6vVChg+zYb4s26VBtrZJfFY2juvSBBfHhpk4Lu613wimKXks89OLBfNQLJBnyjlpHNI6QXazHJee+ZCByp+y+xSd55LZIw+uY43K6pVzyYLuU5mB1/4q/XusLS46+mLvOftVec3BY3M7vLfTFb0k6JcbOtGpMxidg3RmUjsJLR+/YKVtjHYR2mrUhQadbZDnHpX3+P2S0PK44LVz63GDyh4zfOys3ahOTdp9jyl6nSZ0krpY+lh7VXVqvbhOI/pUdmmi+lT0GNGl/Y6julQdj549LmDU7g9W8ff6OeH4txXzZ353fZAQxw//fhzFjTtQvJw87L2Yz3AyQ3Z8TXLKSr3nOcL7QYIXMp/SgTnKKTF7WXvPKcXarketnCOOPRS+bq5mPGuVcxb4fql2/d2D0cNGiXutYGXsxWZ9TUOpgs07Xx5FuaZg8rL05DnLkN2TxZPbg2UODNn8LMOU+R+aMDeTncmM5mbyPJmWNS2YcyGRZcmz5GBNkSHl9O6Q8eY823vg2hjqvYmcr+RnFfTMejWdjfwyPmcnPaBXdnyFR6+xcE3aOo5b0+bGePa37KutrVv2mZvwPQ9uLUq6B+K5N+K9RxLRDoe2O3VzodrP6C2KrMdvnY/bduLYSL3WpVOT1msd+kid1r0L7lXdJcr4UUVSD9hlyuOhdfio0qH1mDO/pcP2GbNX8E/FnWGfknmpmx3c0rkRYY7yNknMc2ON8o44DzBnhLU3J8Xo4YzweRg5PitjhO3CIj6JMcoFlWXj+DJMFr6eXJb1sCgTxZVlyfJgriwLxeNlacpyQJ4oA8URYWjKMmSys/lTZU+RmckdnTkyb1TWiJw5Z3B+1Pu8s97a+8i9vpb3pmNvLsfjZeGv9KvyqvDZVE63EI9R6+rauvtcRf07Fq/OM+r+oJ4VtE/RjpWk62n4utOyXkjdX+Dm5r6Afgak9Rx5/HocQ+nYVXSz9It2inar6qV1y/bydKvsRPXbWdRH6jWiD1TPLrCT5ffUOnSx/s6dQxdrh3XrIb3fo0enyg5W9soOUeb7Fr+/FvByV7BHeZsizCPOG8zZxF3XTXmeSKzStejoc8PCOZo1yjgFJ8fG8UUYo3wRthF8Ua7ebFGmCFuGqwePhyvC0osnwlHNEmWoPJ+X+bsmZNgVzM9m75oge9fAXCovkmvNq8iy5HE5lVl4fTCTQeVQa5BVGT28ty34tdOMb7WntMbr9azysvhoXlkP63jKQ1s758Zb1t3xOOt6fZNnf+29Pp79PO9p6qUd4Os+h54r0lMr/RB8z+lJgx4X5Om31M8KdQeh2wt1m9L9UYf2KHqI0EGg3YxeF/Q+Qrjj6PPzh4rguZs5L73nZu9elCKdIj9zozrhLu3cn0unTB/qZ3rKPtHzzfr7KtPF0yfSw/N7F3aJ9LB0+bOVPB32BHv06ODlx393eTpE+fetGCnuLL+1Q4bbogi3hb0nd4TXwk3xvB9pNK/E3K5JKU6KN3tOWFg5XngNzbE23t7nbgWnlbHi+GPWuTI2zh58HKOHbY+DzcNXMW/VXBXHs5JpXXja6+BKFo1H4tB4qjjaa36JgWPJMhxkZGXAazQeBi77oJD9UDL7/YZsKR/n3mHM1PK0XGoNrCqTyu2ZhfPwml511sFADlyD8+Ro/reDr7uRMv54nQ97wwwu07qmynlzeRZfj+duA6PXc45eIzzg+rFnvLQO3RQdWzGmcn/rvpb9tH2o57m1fOlxzz0PrF8L+m+Hvom0fOyNYu1VdN1Krwr6kqDPKbpS0J2K7lX0a+b4QF23sHW8yqHPO3QToe+stPz+boPuItSOX69z0yN8znnG4D5Q1l49u2VEHS/YS+tU3e1bxZ2grJ2+RSjSo8Knog/XSePhxnA+2j5cj9bFeq5JfUaqosccuuAOXv4pO1B/91Twf5tQJTMnyCRdU/wTI4o7K8vf/9p10L0C81TsGdZezF5eK2c1s+d8iDBWcHrO2yhjlrNdZ9+NvofKsGU4v2NQhE96PfVt8NWSr+nOJA+lKq5KzZEpy1XF8BugqVh+w2gUB5ffg0HKsorLvqlDliS8VnLlSiMzYW6vbClz+fznOubgPLg2V50Bs7R1QU0jciwZvXv09J+bb7Un53VVkddVAS/Ow+OT9WjjXl28fe2aWr9/VZA0tuc46/6vBva37LNOgvc42r/f/XBQ5xv1EUXHGfQnjI4VdLqgl4BOYvROo54GOlLRUYykHhFx86XNs3asrMd8qeh5tXOCbucO6PXhQC/LzwbXp2mqTlXH6VxGc+hjOT4cv9bpnJWifc50dHm+uMe5gB12iXSw9ngeiOJvv6MjPbB6dHh+wXeAf8dU8Hs6WPgxe+N/mlCW29NDY6e4m3pzS+wSt4fZyu1h5tgjzBQvx/yBJC9mbrz4+svD2q4BKdamLO+Zi7eztutJCye+XuU4P5DgPAdxtrnkODXGJsyX5cRzia/POUbp+r8XI8XXGKdia+Je30A27XVTDzaKyTpXElOGb25MvVlOXCnDYnndbeWwsIxg0Hgi+RkGyHLGwn8uNJ2UyD5xlT11ricTypt5YjIPqjqvIiubY82aOkPzt2T05O/FHfFs66xWz0o/i4/kp/lgD87Lw8H5RMZDn+hYvEZuHfPSoDFefyzqngD1PLWfdH9Buv/QQ+0119FAxzP6CaFnGP17Upn/twbqWCSum7VjtlevbpFeWIdrrx9P3Ad2qurTNEWXyj4/JjSyh7WL97hInTKs8HONqB5Sh+OSHaCy/FDweXhvBrNX81M92mPPoq8cO+6g3eurYJckMWrS7lHOnZu7B9mLOcOt3QdeJ17M+pGJWS2c8L0Cc+M8bvH29zPMjZF6/8gIvvvB1/sdbFHGr6P8rzO6n5CHy8PIMUS4rEyezAyTlaeSiePxsFTxUCx/qBwVDH+pyJNtzdcyJRYuV8uOZjZ5c88fmHk+Uq88nJPtCP3PA99TOdG88wRVZEj+2QzNO+pv8fV6Wz2tvh4/zdPrJflVeEU8oE97r1XEg3pfXMV4i4/2nkhqjPZvKfC+ln9/gffV9rfua9nPu0/kOekx+GfqM/bwvY6s3i3oPRv6BaE/3dAfIb0o6ElF8LMjRvRqonpVd4P9ssfO0knq1eu4Rfv8h7HPfwLhPt5e1uMV6QJl6dJk6ZPtFO3B9aF6cF2qj8/xiNXCj7tw/N4eUh9Lj+ONzFgaf6THOnWoOg4R9meApjyHPHP/DCGO+0dO9qcC3G0dW+LjRPFCacxPIb240D/b8CeMvMyYlWLm5piSldczv88InJi3ktXL6OH9kYOT4x3BCFk1Pooxw+dhtLBRrKPmL8I313nzcOD3m/TiknIpjqb2WWwtF35fxeN5j5T3M3ItirxXK/J5vdUcmc8znQMDxTEyG+ePzn7OmVuV+dwEmXPLqsgbkdM7o6f/OvlWe1b6VR2jCo99SZ99Bg9trDReG0eNtYzRxkXfn3q4acdKFwFtLdQupFuLpH3uSpN1HvBn1VXoDkbcZ/1YZe3Wo5PUK9PPcsx69bH2avoHo7ROvftYOlm7aH3m0CXa59mBHaqPCezy7Iw6RHrcNpDf0mPO/D3On97MPwWaM/dPGVXN960DWKvmuV1vwcz7VqpirOJtrPc5FOXkeK2MXs7GGmGErDBfYosyZvgirwNG8c2VbY5cc2MawWNlWmeWCIfGMoJh50oV+TsZSblc/gVGadmQgXrck0Vla7mUonltnahHxjYgvC5VlbMtmOVh54RzIvPi8ZcyqHmo8Pf4Sb67Onlu7eDn9eS8In6aj9VL87D4aOMlD8tYbryFnRrrzbTmbCX236rsb/XdatxHy5uLLgJfdyAdY9AVRfqyU9cyuk6R5Z7IvYLuNOhKRtrnAn1JkOXzZTK97lkp0kvrJvWSumV7WTpFe2mduF6ZTvcs8scp2wl3s/TJdIn0+aKzS1Okyz2LuuPSunwRKdol2kHqYelwJdEh0sPageLPdqD4vR00/r9fycp/dXL+PfzXJrgh+9VAvbnbNQBek7gNMGvsVxOKMlu4OeZbCWaKeyQvvM6ysFp5NWYPL3WdGGH1cl6zkpVV48wwcpzXLGycjZW67vYwSnwU5zULH6PEx7FBRg8fZpP4uNcsVjYLV2OjuLxsFi4r09UCE8c1JZOHp4olyzOKBfNgjqrzeKkvGDl6MWj5HENVtjUfrpdI54EnV8vGazVcrrevlg0zdxX1lDIr8qgsLQ+uxy0zLirOonLg+5kjGTgHZ1xEKNrjioS/xP+Fjt7Yl/L0+lo8o5xWv5FelM9ID8t4vB6uzQM37hhlnLYG7x2D95f2tfpW7CM973kcPwb/3L5f3uPQ7hfc6NRXGN2g6FMGvcLo4xv61UqZrY3/L4Om2O4C2rsSPFbSPZKrAvr0Sp8ndJNRdyu6ixDVDfaLdJH6wZ7WXtFudzG9qjpRvT5d2MvaqWeXyk6WPiO6VPSRulR1+OpKVV0sPdp2Y3EHrUvmeFD8rYO3x1cFdu1YVPDjYwDlmWdOFPfXCFn5rewcv5UbiuK18Es/uxL3jUHOCDfFPgWzlZVjXgfedn05ktXL+bXF/78W5linnk/IOYKxch7bNiUffs3Ta+56cVGvQ3tw/d1KFFfbuNfFHjYPC8fTmCw8EpOWTYmbHysL5NGyPCwejmyuNB+euZgqv0culd3WhapypXUcbk2qV66UeUOnniPztLW+qiwtJ5I1OqPa33scrP4RZs0berY13sxcUH6ap9cr4hfxwV6cR1sDp8b/ShiP19CpsU1wLLcGT41r4sa8EhhD7cvtn93X4yU9Tz2+MD6+AI9ZtscNOhTQYw7t7agDjH4e0MMb+t4AVfRresGglxW9S9AThP5NkOV8g+p1XljOy39F8pz/U3fD7BZVdavq8Vqwh7dX72P1GtIcOlX0qOqi9TkculSeY68JHXp2qeogcffo0FTBb2Wfgh+eGxHeXuxW7qxGMs+Nd6l2/UXxfi/J+gOgKk7M2q4R23Wwl0tTy/Qycte30jW8h4vjzKgn45z5Ktgan/Y6bap5m+Ocze08m9PPZi8WL9McOCzrH+uaL62TvGumuT3ypMy5543KyuQ8AnweAarKeITRyyv9YGFbJ3zZ6PsI46dpKt+IZ1tDllg93lY/i2eV18+NXhUelM8LwfEvBMd6x71AjLHs692/cj8q9wDhcWCQjl3pKKQtio4olpaHhXmh9oN+8PXwk4peFAQ/N/UXjN6z0rsJHS3oKPDVoqNXx8zarb02lPq9aOiFu2mdIoK9pD7WXpZOTT36NEmdqPt6nk5UF6lPtovUh7tP2aOLlVX7vUF1ke65VvbwsGu/D3EPbwfYg+PHHar4m6z8sAN8TGP38HvZvfyUsuwR5qZK7vcCcdzatYWVO8KLud9LiJrnyLVQJTPFiXmlOY5ek/XkpeY3cx25DpxHFHNqx34Uo2ceR/K1NRRt7ir5PFwUm3StkGHLzJd0HZb5XfPEIjZP2nVhlIni4db8rMcsyvOEkM2x9JgXD8Mfr+SdD43FysDlW/4+lxisuT36WzOjvT25VGZl36qe1nMdr7P37AdzuKyKXjAjmqP1yfprGT34txi8o9xbnL5TeXJ+lvUJyguug0fnD6/RWzywT8TDM17Kj+ZG8jxjtjj9rftS+1H7HBD2OYCetzwHH8eP4T/DewHwMaq39jPovVaJSsrDrMcC7Ve6zbkX7taj19w6Zfr06OI9/6g+nnNsTl1gn/0z6zCiR29+b4fWYy7sPfjnwO1hH8VbwT2aNXuezJGV4z1qk3XtOefOOGe+CNcItjnO2dyY5nLsovNy5GCOI1E21IOD8iU9mODQsj35HoaKXJytMVgyM7kPOjKmztSynmayni4QzHiayKrI4HQyULX3O1c6OSDJDyviD3M436x3D9+RnpV+VV4VxyMy9qSVluNPBbKOazrVOF4bxykzxrO/ts9LK2nPc/vA509b6XRC3HPU49KfTwNf9xpl+XeOS/2zQ3Dcw0je/0vrAFBbL6/o5OlD9cO9Ij33I03VB0rrpfXDnaj/H/suxL7o2KeiF9VnsaD/X228VfdY6rsrWTtR2i8wS1sVO6dIl+j2gEEab1WX7Gbpkuk0J/5Mn2r2DHe0x9y4Pfxz4rVwZ7eRzFVbb97KrRfryC3COHqbMxve5sqFtzkybW6b2+a2uW1um9vmtrltbofHdsJKn3Xqsg1dntD1hP42Ke2z5bOfN/8VQTcw+pRDrxD6+OL3nzePt4pev1W6ZTt9UulFdcv2+i1Qr05NVJ8ma6fGqnXhOmX6fJIQ1YXrg3/uKF5Jf7OS1Cfag+uDt9YD/x6JdoF9PD2kDlQP3IX7nRjtAGXpoPFHOzRlOtyA/oy558LPzT8lKzPHbWXPnjuUMsyV3B5mC3eGed14ry9mzfC+JbDCa8zenH+NRHE2VomzKcLWsuH3FBvHyTFW83lE8b1l4PMyRtggH8XGcVn5okyXClwak8SV4YGamgnzQCYLC2SCbFUsjcfDgueogiHKcX3hPCz15mGeP8dsb242882VuDWiXh2ldSlvnnYcLethvXJa1uVJfy3jciVD826KeFszIt6fAPL6Wjw532rPjBf2s3pRPtCvwqdyPF7z1sZfRoyB4saNGNNj34p9pOe557z3KpZq9zmo9dfsfQfq74nofZHLFvp5NLIb7jeyV+vWq1dTtlPkePXuFOk15z7RHt5Oc+nCdbB0uWUlqse1QJVdNF6pQ+PFf4YdrnXI2yHCDnWLIA93tEMv/ii7p8s6cv8hMffmpZjnzIp5qzm/jJRlrZ5LzFfBOYIvw+jh+gbQkudmIInNy+mdr28gRbgktsgxzDJdAQRZPgMUZfHyXIH0GackjgyLl6Mpy4HnI8ISZajIlhi4fCo3yyDlWzIr577lWjO9uRWZ2Z4980ZlcfNYmZPJmNo/6j2FL/c7sJJzexHf9gKv7QafHUCUj8cDjttBeGj5lLixPcdF9z/GsO8xQNK+lv0yz3sft2ivojeK9c3Ouh1I61bZb7MXr98B4cc8nSp6VR2P3wmy9vkXIMj4j4reAF+rmCm9byVPDyitB5aXz8qf7WHt0pt/zh0oVi+/xN6L38o9J3YPc5Z7qYcK2D28rxcxN2HWgyvtBoKsrwON4H2I0UGk3YQwr0UW1u+jr15WibmK8/sGWTmjvBKjha+Sk2KV+P4nwacxWvg0NqhRfLsdTFa+CjaK57GVRnBpPI8t8jweJo7lsUUdi5cHZ1s5ovNCsUgMPY4NZsjkZxmmyu6ZuyeQqeVZMnFuj457CPXIonL2GHKsWZy/JcNyrKbyz3g/ulKV76OEoOchoyflQ3keAsJemgf2O0T4HXL6PEr4QI3yyIyPjq0aU7W/dd/23OOE2j7Uc1PqfwGR6JRL 242 | 243 | 244 | -------------------------------------------------------------------------------- /data/lh.aparc.annot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwagstyl/matplotlib_surface_plotting/9dcb13dbbd8d0ed765089486ef28dce225ebebb2/data/lh.aparc.annot -------------------------------------------------------------------------------- /data/lh.inflated: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwagstyl/matplotlib_surface_plotting/9dcb13dbbd8d0ed765089486ef28dce225ebebb2/data/lh.inflated -------------------------------------------------------------------------------- /data/lh.sulc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwagstyl/matplotlib_surface_plotting/9dcb13dbbd8d0ed765089486ef28dce225ebebb2/data/lh.sulc -------------------------------------------------------------------------------- /data/lh.thickness: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwagstyl/matplotlib_surface_plotting/9dcb13dbbd8d0ed765089486ef28dce225ebebb2/data/lh.thickness -------------------------------------------------------------------------------- /examples/hcp_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 8, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import os, sys\n", 12 | "sys.path.append('../matplotlib_surface_plotting/')\n", 13 | "\n", 14 | "from matplotlib_surface_plotting import plot_surf\n", 15 | "import nibabel as nb\n", 16 | "import numpy as np" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 9, 22 | "metadata": { 23 | "collapsed": true 24 | }, 25 | "outputs": [], 26 | "source": [ 27 | "import numpy as np\n", 28 | "import matplotlib.pyplot as plt\n", 29 | "from matplotlib.collections import PolyCollection\n", 30 | "from matplotlib import cm\n", 31 | "\n", 32 | "def normalize_v3(arr):\n", 33 | " ''' Normalize a numpy array of 3 component vectors shape=(n,3) '''\n", 34 | " lens = np.sqrt( arr[:,0]**2 + arr[:,1]**2 + arr[:,2]**2 )\n", 35 | " arr[:,0] /= lens\n", 36 | " arr[:,1] /= lens\n", 37 | " arr[:,2] /= lens \n", 38 | " return arr\n", 39 | "\n", 40 | "def normal_vectors(vertices,faces):\n", 41 | " norm = np.zeros( vertices.shape, dtype=vertices.dtype )\n", 42 | " tris = vertices[faces]\n", 43 | " n = np.cross( tris[::,1 ] - tris[::,0] , tris[::,2 ] - tris[::,0] )\n", 44 | " n=normalize_v3(n)\n", 45 | " return n\n", 46 | "# norm[ faces[:,0] ] += n\n", 47 | "# norm[ faces[:,1] ] += n\n", 48 | "# norm[ faces[:,2] ] += n\n", 49 | " # return normalize_v3(norm)\n", 50 | "\n", 51 | "\n", 52 | "def frustum(left, right, bottom, top, znear, zfar):\n", 53 | " M = np.zeros((4, 4), dtype=np.float32)\n", 54 | " M[0, 0] = +2.0 * znear / (right - left)\n", 55 | " M[1, 1] = +2.0 * znear / (top - bottom)\n", 56 | " M[2, 2] = -(zfar + znear) / (zfar - znear)\n", 57 | " M[0, 2] = (right + left) / (right - left)\n", 58 | " M[2, 1] = (top + bottom) / (top - bottom)\n", 59 | " M[2, 3] = -2.0 * znear * zfar / (zfar - znear)\n", 60 | " M[3, 2] = -1.0\n", 61 | " return M\n", 62 | "\n", 63 | "def perspective(fovy, aspect, znear, zfar):\n", 64 | " h = np.tan(0.5*np.radians(fovy)) * znear\n", 65 | " w = h * aspect\n", 66 | " return frustum(-w, w, -h, h, znear, zfar)\n", 67 | "\n", 68 | "def translate(x, y, z):\n", 69 | " return np.array([[1, 0, 0, x], [0, 1, 0, y],\n", 70 | " [0, 0, 1, z], [0, 0, 0, 1]], dtype=float)\n", 71 | "\n", 72 | "def xrotate(theta):\n", 73 | " t = np.pi * theta / 180\n", 74 | " c, s = np.cos(t), np.sin(t)\n", 75 | " return np.array([[1, 0, 0, 0], \n", 76 | " [0, c, -s, 0],\n", 77 | " [0, s, c, 0], \n", 78 | " [0, 0, 0, 1]], dtype=float)\n", 79 | "\n", 80 | "def yrotate(theta):\n", 81 | " t = np.pi * theta / 180\n", 82 | " c, s = np.cos(t), np.sin(t)\n", 83 | " return np.array([[ c, 0, s, 0], \n", 84 | " [ 0, 1, 0, 0],\n", 85 | " [-s, 0, c, 0], \n", 86 | " [ 0, 0, 0, 1]], dtype=float)\n", 87 | "\n", 88 | "def zrotate(theta):\n", 89 | " t = np.pi * theta / 180\n", 90 | " c, s = np.cos(t), np.sin(t)\n", 91 | " return np.array([[ c, -s, 0, 0], \n", 92 | " [ s, c, 0, 0],\n", 93 | " [0, 0, 1, 0], \n", 94 | " [ 0, 0, 0, 1]], dtype=float)\n", 95 | "\n", 96 | "def shading_intensity(vertices,faces, light = np.array([0,0,1]),shading=0.7):\n", 97 | " \"\"\"shade calculation based on light source\n", 98 | " default is vertical light.\n", 99 | " shading controls amount of shading.\n", 100 | " Also saturates so top 20 % of vertices all have max intensity.\"\"\"\n", 101 | " face_normals=normal_vectors(vertices,faces)\n", 102 | " intensity = np.dot(face_normals, light)\n", 103 | " intensity[np.isnan(intensity)]=1\n", 104 | " shading = 0.7 \n", 105 | " #top 20% all become fully coloured\n", 106 | " intensity = (1-shading)+shading*(intensity-np.min(intensity))/((np.percentile(intensity,80)-np.min(intensity)))\n", 107 | " #saturate\n", 108 | " intensity[intensity>1]=1\n", 109 | " #flat maps have lots of nans which need to become 1\n", 110 | " intensity[np.isnan(intensity)]=1\n", 111 | " return intensity\n", 112 | "\n", 113 | "def f7(seq):\n", 114 | " #returns uniques but in order to retain neighbour triangle relationship\n", 115 | " seen = set()\n", 116 | " seen_add = seen.add\n", 117 | " return [x for x in seq if not (x in seen or seen_add(x))];\n", 118 | "\n", 119 | "\n", 120 | "def get_ring_of_neighbours(island, neighbours, vertex_indices=None, ordered=False):\n", 121 | " \"\"\"Calculate ring of neighbouring vertices for an island of cortex\n", 122 | " If ordered, then vertices will be returned in connected order\"\"\"\n", 123 | " if not vertex_indices:\n", 124 | " vertex_indices=np.arange(len(island))\n", 125 | " if not ordered:\n", 126 | "\n", 127 | " neighbours_island = neighbours[island]\n", 128 | " unfiltered_neighbours = []\n", 129 | " for n in neighbours_island:\n", 130 | " unfiltered_neighbours.extend(n)\n", 131 | " unique_neighbours = np.setdiff1d(np.unique(unfiltered_neighbours), vertex_indices[island])\n", 132 | " return unique_neighbours\n", 133 | "\n", 134 | "def get_neighbours_from_tris(tris, label=None):\n", 135 | " \"\"\"Get surface neighbours from tris\n", 136 | " Input: tris\n", 137 | " Returns Nested list. Each list corresponds \n", 138 | " to the ordered neighbours for the given vertex\"\"\"\n", 139 | " n_vert=np.max(tris+1)\n", 140 | " neighbours=[[] for i in range(n_vert)]\n", 141 | " for tri in tris:\n", 142 | " neighbours[tri[0]].extend([tri[1],tri[2]])\n", 143 | " neighbours[tri[2]].extend([tri[0],tri[1]])\n", 144 | " neighbours[tri[1]].extend([tri[2],tri[0]])\n", 145 | " #Get unique neighbours\n", 146 | " for k in range(len(neighbours)): \n", 147 | " if label is not None:\n", 148 | " neighbours[k] = set(neighbours[k]).intersection(label)\n", 149 | " else :\n", 150 | " neighbours[k]=f7(neighbours[k])\n", 151 | " return np.array(neighbours)\n", 152 | "\n", 153 | "def adjust_colours_pvals(colours, pvals,triangles,mask=None):\n", 154 | " \"\"\"red ring around clusters and greying out non-significant vertices\"\"\"\n", 155 | " if mask is not None:\n", 156 | " verts_masked = mask[triangles].any(axis=1)\n", 157 | " colours[verts_masked,:] = np.array([0.86,0.86,0.86,1])\n", 158 | " neighbours=get_neighbours_from_tris(triangles)\n", 159 | " ring=get_ring_of_neighbours(pvals<0.05,neighbours)\n", 160 | " if len(ring)>0:\n", 161 | " ring_label = np.zeros(len(neighbours)).astype(bool)\n", 162 | " ring_label[ring]=1\n", 163 | " ring=get_ring_of_neighbours(ring_label,neighbours)\n", 164 | " ring_label[ring]=1\n", 165 | " colours[ring_label[triangles].any(axis=1),:] = np.array([1.0,0,0,1])\n", 166 | " grey_out=pvals<0.05\n", 167 | " verts_grey_out= grey_out[triangles].any(axis=1)\n", 168 | " colours[verts_grey_out,:] = (1.5*colours[verts_grey_out] + np.array([0.86,0.86,0.86,1]))/2.5\n", 169 | " return colours\n", 170 | "\n", 171 | "def frontback(T):\n", 172 | " \"\"\"\n", 173 | " Sort front and back facing triangles\n", 174 | " Parameters:\n", 175 | " -----------\n", 176 | " T : (n,3) array\n", 177 | " Triangles to sort\n", 178 | " Returns:\n", 179 | " --------\n", 180 | " front and back facing triangles as (n1,3) and (n2,3) arrays (n1+n2=n)\n", 181 | " \"\"\"\n", 182 | " Z = (T[:,1,0]-T[:,0,0])*(T[:,1,1]+T[:,0,1]) + \\\n", 183 | " (T[:,2,0]-T[:,1,0])*(T[:,2,1]+T[:,1,1]) + \\\n", 184 | " (T[:,0,0]-T[:,2,0])*(T[:,0,1]+T[:,2,1])\n", 185 | " return Z < 0, Z >= 0\n", 186 | "\n", 187 | "\n", 188 | "\n", 189 | "\n", 190 | "def plot_surf(vertices, faces, overlay, rotate=[270,90], cmap='viridis', filename=None, label=False,\n", 191 | " vmax=None, vmin=None, x_rotate=270,z_rotate=0, pvals=None, colorbar=True, title=None, mask=None, base_size=6,\n", 192 | " flat_map=False,\n", 193 | " ):\n", 194 | " \"\"\"plot mesh surface with a given overlay\n", 195 | " vertices - vertex locations\n", 196 | " faces - triangles of vertex indices definings faces\n", 197 | " overlay - array to be plotted\n", 198 | " cmap - matplotlib colormap\n", 199 | " rotate - 270 for lateral on lh, 90 for medial\n", 200 | " \"\"\"\n", 201 | " vertices=vertices.astype(np.float)\n", 202 | " F=faces.astype(int)\n", 203 | " vertices = (vertices-(vertices.max(0)+vertices.min(0))/2)/max(vertices.max(0)-vertices.min(0))\n", 204 | " if not isinstance(rotate,list):\n", 205 | " rotate=[rotate]\n", 206 | " if not isinstance(overlay,list):\n", 207 | " overlays=[overlay]\n", 208 | " else:\n", 209 | " overlays=overlay\n", 210 | " if flat_map:\n", 211 | " z_rotate=90\n", 212 | " rotate=[90]\n", 213 | " \n", 214 | " #change light source if z is rotate\n", 215 | " light = np.array([0,0,1,1]) @ yrotate(z_rotate)\n", 216 | " intensity=shading_intensity(vertices, F, light=light[:3],shading=0.7)\n", 217 | " print(intensity.shape)\n", 218 | " #make figure dependent on rotations\n", 219 | " \n", 220 | " fig = plt.figure(figsize=(base_size*len(rotate)+colorbar*(base_size-2),(base_size-1)*len(overlays)))\n", 221 | " if title is not None:\n", 222 | " plt.title(title, fontsize=25)\n", 223 | " plt.axis('off')\n", 224 | " for k,overlay in enumerate(overlays):\n", 225 | " #colours smoothed (mean) or median if label\n", 226 | " if label:\n", 227 | " colours = np.median(overlay[F],axis=1)\n", 228 | " else:\n", 229 | " colours = np.mean(overlay[F],axis=1)\n", 230 | " if vmax is not None:\n", 231 | " colours = (colours - vmin)/(vmax-vmin)\n", 232 | " colours = np.clip(colours,0,1)\n", 233 | " else:\n", 234 | " colours = (colours - colours.min())/(colours.max()-colours.min())\n", 235 | " vmax = colours.max()\n", 236 | " vmin = colours.min()\n", 237 | " C = plt.get_cmap(cmap)(colours) \n", 238 | " if pvals is not None:\n", 239 | " C = adjust_colours_pvals(C,pvals,F,mask)\n", 240 | " \n", 241 | " \n", 242 | " #adjust intensity based on light source here\n", 243 | "\n", 244 | " C[:,0] *= intensity\n", 245 | " C[:,1] *= intensity\n", 246 | " C[:,2] *= intensity\n", 247 | " for i,view in enumerate(rotate):\n", 248 | " MVP = perspective(25,1,1,100) @ translate(0,0,-3) @ yrotate(view) @ zrotate(z_rotate) @ xrotate(x_rotate) @ zrotate(270*flat_map) \n", 249 | " #translate coordinates based on viewing position\n", 250 | " V = np.c_[vertices, np.ones(len(vertices))] @ MVP.T\n", 251 | " \n", 252 | " V /= V[:,3].reshape(-1,1)\n", 253 | " \n", 254 | " V = V[F]\n", 255 | " \n", 256 | " #triangle coordinates\n", 257 | " T = V[:,:,:2]\n", 258 | " #get Z values for ordering triangle plotting\n", 259 | " Z = -V[:,:,2].mean(axis=1)\n", 260 | " #sort the triangles based on their z coordinate. If front/back views then need to sort a different axis\n", 261 | "#sort the triangles based on their z coordinate. If front/back views then need to sort a different axis\n", 262 | " front, back = frontback(T)\n", 263 | " T=T[front]\n", 264 | " s_C = C[front]\n", 265 | " Z = Z[front]\n", 266 | " I = np.argsort(Z)\n", 267 | " T, s_C = T[I,:], s_C[I,:]\n", 268 | " ax = fig.add_subplot(len(overlays),len(rotate)+1,2*k+i+1, xlim=[-.9,+.9], ylim=[-.9,+.9],aspect=1, frameon=False,\n", 269 | " xticks=[], yticks=[])\n", 270 | " #s_C[:,3]=0.3\n", 271 | " #print(s_C)\n", 272 | " collection = PolyCollection(T, closed=True, linewidth=0,antialiased=False, facecolor=s_C)\n", 273 | " collection.set_alpha(1)\n", 274 | " ax.add_collection(collection)\n", 275 | " plt.subplots_adjust(left =0 , right =1, top=1, bottom=0,wspace=0, hspace=0)\n", 276 | " if colorbar:\n", 277 | " cbar = fig.colorbar(cm.ScalarMappable( cmap=cmap), ticks=[0,0.5, 1],cax = fig.add_axes([0.7, 0.3, 0.03, 0.38]))\n", 278 | " cbar.ax.set_yticklabels([np.round(vmin,decimals=2), np.round(np.mean([vmin,vmax]),decimals=2),\n", 279 | " np.round(vmax,decimals=2)])\n", 280 | " cbar.ax.tick_params(labelsize=25)\n", 281 | " if filename is not None:\n", 282 | " fig.savefig(filename,bbox_inches = 'tight',pad_inches=0,transparent=True)\n", 283 | " return \n", 284 | "\n", 285 | "\n", 286 | "\n" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": null, 292 | "metadata": { 293 | "collapsed": true 294 | }, 295 | "outputs": [], 296 | "source": [] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": 10, 301 | "metadata": { 302 | "collapsed": true 303 | }, 304 | "outputs": [], 305 | "source": [ 306 | "#vertices = (vertices-(vertices.max(0)+vertices.min(0))/2)/max(vertices.max(0)-vertices.min(0))\n", 307 | "#vertices = np.roll(vertices,1,axis=1)" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 11, 313 | "metadata": { 314 | "collapsed": true 315 | }, 316 | "outputs": [], 317 | "source": [ 318 | "# vector_file=nb.load('../data/MyelinMap_inflated_vectors.L.func.gii')\n", 319 | "# vectors=np.array([vector_file.darrays[0].data,\n", 320 | "# vector_file.darrays[1].data,\n", 321 | "# vector_file.darrays[2].data])" 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 12, 327 | "metadata": {}, 328 | "outputs": [], 329 | "source": [ 330 | "surf=nb.load('../data/fs_LR.32k.L.inflated.surf.gii')\n", 331 | "vertices,faces = surf.darrays[0].data,surf.darrays[1].data" 332 | ] 333 | }, 334 | { 335 | "cell_type": "code", 336 | "execution_count": 13, 337 | "metadata": {}, 338 | "outputs": [], 339 | "source": [ 340 | "overlay = nb.load('../data/S1200.MyelinMap.L.func.gii').darrays[0].data" 341 | ] 342 | }, 343 | { 344 | "cell_type": "code", 345 | "execution_count": 14, 346 | "metadata": {}, 347 | "outputs": [], 348 | "source": [ 349 | "surf=nb.load('../data/fs_LR.32k.L.flat.surf.gii')\n", 350 | "vertices,faces = surf.darrays[0].data,surf.darrays[1].data" 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 15, 356 | "metadata": { 357 | "collapsed": true 358 | }, 359 | "outputs": [], 360 | "source": [ 361 | "# vertices[:,2]+=vertices[:,0]\n", 362 | "# vertices[:,0]=0" 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": 16, 368 | "metadata": {}, 369 | "outputs": [ 370 | { 371 | "name": "stderr", 372 | "output_type": "stream", 373 | "text": [ 374 | "/home/kwagstyl/anaconda2/envs/padl/lib/python3.7/site-packages/ipykernel_launcher.py:9: RuntimeWarning: invalid value encountered in true_divide\n", 375 | " if __name__ == '__main__':\n", 376 | "/home/kwagstyl/anaconda2/envs/padl/lib/python3.7/site-packages/ipykernel_launcher.py:10: RuntimeWarning: invalid value encountered in true_divide\n", 377 | " # Remove the CWD from sys.path while we load stuff.\n", 378 | "/home/kwagstyl/anaconda2/envs/padl/lib/python3.7/site-packages/ipykernel_launcher.py:11: RuntimeWarning: invalid value encountered in true_divide\n", 379 | " # This is added back by InteractiveShellApp.init_path()\n", 380 | "/home/kwagstyl/anaconda2/envs/padl/lib/python3.7/site-packages/ipykernel_launcher.py:80: RuntimeWarning: divide by zero encountered in true_divide\n", 381 | "/home/kwagstyl/anaconda2/envs/padl/lib/python3.7/site-packages/ipykernel_launcher.py:80: RuntimeWarning: invalid value encountered in true_divide\n" 382 | ] 383 | }, 384 | { 385 | "name": "stdout", 386 | "output_type": "stream", 387 | "text": [ 388 | "(59013,)\n" 389 | ] 390 | }, 391 | { 392 | "data": { 393 | "image/png": "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\n", 394 | "text/plain": [ 395 | "
" 396 | ] 397 | }, 398 | "metadata": { 399 | "needs_background": "light" 400 | }, 401 | "output_type": "display_data" 402 | } 403 | ], 404 | "source": [ 405 | "plot_surf(vertices,faces,overlay,rotate=90,flat_map=True,\n", 406 | " vmin=1,vmax=2)" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 647, 412 | "metadata": {}, 413 | "outputs": [ 414 | { 415 | "data": { 416 | "text/plain": [ 417 | "array([ 1.0000000e+00, 0.0000000e+00, -1.8369702e-16, 1.0000000e+00])" 418 | ] 419 | }, 420 | "execution_count": 647, 421 | "metadata": {}, 422 | "output_type": "execute_result" 423 | } 424 | ], 425 | "source": [ 426 | "light = np.array([0,0,1,1]) @ yrotate(270)\n", 427 | "light" 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": 584, 433 | "metadata": {}, 434 | "outputs": [ 435 | { 436 | "data": { 437 | "text/plain": [ 438 | "" 439 | ] 440 | }, 441 | "execution_count": 584, 442 | "metadata": {}, 443 | "output_type": "execute_result" 444 | }, 445 | { 446 | "data": { 447 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAD5CAYAAAAk7Y4VAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAZjUlEQVR4nO3df5AU93nn8fcDLDpB5CCiFVFABIKJL1KBQbclcHFxUpGwZWOLlc6S5SCfkvhMXCdfGcuxBBIVZBc4yIqJcpcrp+DkK10JW8j6MeKCg4191lWFAmLQrlijHwFkjJhDQAoTEUQBC8/9Mb14WM3+nO7+9o/Pq2qLmZ6Z7ket2c989+nvdJu7IyIixTcidAEiIpIOBb6ISEko8EVESkKBLyJSEgp8EZGSUOCLiJTEqDhWYmZfBP4T4EAX8MfANcBTwK8Bu4BPu/vZ/tZz1VVX+ZQpU+IoSUSkNHbt2vXP7t460POs2Xn4ZjYR+AfgOnc/bWZPA98DPgo85+5PmdnfAi+7+zf7W1dbW5vv3LmzqXpERMrGzHa5e9tAz4urpTMKuNzMRgFjgMPAHwDPRI8/AbTHtC0RERmGpgPf3avAXwIHqQX9v1Br4Zxw9+7oaYeAic1uS0REhq/pwDezK4GFwFTgN4CxwC1DeP1iM9tpZjuPHTvWbDkiItKHOFo6NwM/c/dj7n4OeA6YB4yLWjwAk4Bqoxe7+1p3b3P3ttbWAY85iIjIMMUR+AeBuWY2xswMuAl4Bfgx8InoOfcAL8SwLRERGaamp2W6+w4zewZ4CegGOoC1wCbgKTNbGS17vNltSXFVOqp85X/v4RfvnLtk+ZVjWljx8etpn53OIaBKR5WHN+7hxOlzfT7HgEVzJ7OyfUYqNYnEpelpmXHStMziW17p4sntB5tax7xp41n/2Q80XUulo8qXv9vJuQtNr+qiMS0j+NrtM1P7gBKBwU/LVOBLoiodVZY9t5vTcaZqZMIVo9nx0PwhvWbRum1s3X889loa0V8CkhYFvgSVZrA2Cv7llS6+s+NNzmfo/d0j7TaVFJ8CX1KVRHukrPSBIEOlwJdUxNGTl8Ebd3kLD9+qDwO5lAJfEpVmy0b6p2MFMtjAj+VsmVIeCvrsceDJ7Qcv/qWllpD0RSN8GZBCPt/UBio+tXSkaXNWbeHIyX4vYSA5pL8AikeBL8Oig7Dlcrd6/4WgHr4MWqWjypee7uR8dj77JSU9vf8RBn84R+FfdAr8EtNoXnpc8F+Gv1o+xaWWTgkp6GUwRhp8485ZCv4cUA9f3kWzbWS41OvPNvXw5SKN6KVZPe2euM5UKmEo8Atu5orNvH3mfOgypCC27j/OlKWb9O3enFLgF5RG9ZKk+m/3jh09klW3zVCvPwcU+AWkUb2k6dTZ8yzZ0Amg0M+4OK5pKxlR6agyZekmhb0EsWRDJ1OWbmLRum2hS5E+aIRfEPPXvMjeo6dClyFysc9/2agRPPIfdLnHLNEIvwBmrtissJfMOdN9gSUbOpn91R9Q6aiGLkfQCD/XKh3Vi71Tkaz6xTvn+KJ6/JmgEX5OKewlT5xf9vjnr3kxdDmlpcDPKYW95NXeo6cU+oEo8HNo6tJNoUsQacreo6eYsnQTc1ZtCV1KqcQS+GY2zsyeMbPXzOxVM/uAmY03sy1mtjf698o4tlVmPdMus3P2I5HmHDl5VsGforhG+H8NbHb3fwu8H3gVWAr8yN2nAz+K7sswLa90qY0jhXXk5FmFfgqaDnwz+1Xgg8DjAO5+1t1PAAuBJ6KnPQG0N7utstJpEqQMNNpPXhzTMqcCx4D/aWbvB3YBXwAmuPvh6DlvARMavdjMFgOLASZPnhxDOcVS6agq7KVUeoIf0Nk5YxZHS2cUcAPwTXefDZyiV/vGayfdb9h6dve17t7m7m2tra0xlFMsauNImW3df1ynaohRHIF/CDjk7jui+89Q+wA4YmbXAET/Ho1hW6Xy3mWajSOydf9xZq7YHLqMQmg68N39LeBNM3tftOgm4BVgI3BPtOwe4IVmt1UmM1dsplvTcUQAePvMeYV+DOI6tcJ/Adab2WjgDeCPqX2YPG1mnwF+DtwZ07YKrdJR5b4NnVwIXYhIxrx95jxTlm5SX78JuqZthmg2jsjgTb96LFvu+/3QZWTCYK9pq2/aZoTCXmRodIqGoVPgZ8CiddsU9iLDsPfoKaYt26TTLw+STo8cmC5cItKc844usThIGuEHtGjdNoW9SEyWbOhUi2cACvxAFq3bxtb9x0OXIVIoPWfhXF7pCl1KJqmlE8CcVVs4cvJs6DJECqvnmNjK9hmBK8kWjfBTprAXSceT2w+qxdOLAj9FCnuRdGnq5qUU+CmZuWKzwl4kgJ6+vk7CpsBPxcwVm3n7zPnQZYiUms68qcBPnMJeJDu27j9e6haPAj9BCnuR7ClzX1+Bn4BKR5WpSzcp7EUyqqyhr8CP2aJ121iyobPx5b1EJDPKGPoK/BjNX/Oivj0rkiNlC30Ffkx0EjSRfCrT6RgU+DHQSdBE8u/J7QcLH/oK/CYtr3SpjSNSEEUPfQV+E3SVKpHiKXLoK/CHSWEvUlxFDX0F/jBUOqoKe5GCK2LoK/CH4YFnd4cuQURSULTQV+AP0fw1L3Km+0LoMkQkJUUK/dgC38xGmlmHmf1ddH+qme0ws31mtsHMRse1rVA0/VKknIoS+nGO8L8AvFp3/xHgr9z9vcAvgM/EuK3UVTqqmn4pUmJFCP1YAt/MJgELgP8R3TfgD4Bnoqc8AbTHsa0QKh1VlmzoDF2GiASW99CPa4T/GHA/0NPc/jXghLt3R/cPARNj2laqFPYiUi/Pod904JvZx4Cj7r5rmK9fbGY7zWznsWPHmi0ndvc/83LoEkQkY9bndFp2HCP8ecCtZnYAeIpaK+evgXFmNip6ziSg2ujF7r7W3dvcva21tTWGcuJT6ahy9rxOdCwil3LI5Si/6cB392XuPsndpwB3Af/H3RcBPwY+ET3tHuCFZreVti893Rm6BBHJqDx++TLJefgPAPeZ2T5qPf3HE9xW7JZXutDgXkT6M2fVltAlDEmsge/uL7r7x6Lbb7j7je7+Xne/w93PxLmtpOXx01tE0nXk5Nlchb6+adtAHntzIhLGkZNnWbRuW+gyBkWB34BG9yIyFFv3H89F6CvweynT9S1FJD55+Ca+Ar9OpaOqc+WIyLBlvZ+vwK+jL1mJSDOOnDyb6S6BAj+iL1mJSBz2Hj2V2dBX4Ef0JSsRiUtWW8MKfGqjew3uRSROM1dsDl3CuyjwUe9eROL39pnzmWvtlD7w1bsXkaRkrZ9f+sBX715EkpSlfn6pA1+9exFJQ1a+hVvqwH/wud2hSxCREti6/ziVjoaXBElVqQP/nXMXBn6SiEgMvrihM3jolzbws/InloiUgwMPb9wTtIZSBn6lo5qLEx2JSLGcOH0u6PZLGfiady8ioYTsLpQu8DXvXkRCCtldKF3gP/CsZuaISFihRvmlCvxKR5Uz3ZqZIyJhhRrllyrwNboXkawIMcovTeBrdC8iWRJilF+awF+yoTN0CSIil0h7lF+KwF9e6QpdgojIu6Q9ym868M3sWjP7sZm9YmZ7zOwL0fLxZrbFzPZG/17ZfLnD8+T2g6E2LSLSrzRPtxDHCL8b+JK7XwfMBe41s+uApcCP3H068KPofup0CgURybIvf7cztW01HfjuftjdX4punwReBSYCC4Enoqc9AbQ3u63h0CkURCTL0jyHY6w9fDObAswGdgAT3P1w9NBbwIQ+XrPYzHaa2c5jx47FWQ5zVm2JdX0iIklIqxMRW+Cb2a8AzwJL3P3t+sfc3amdLO5d3H2tu7e5e1tra2tc5bC80sWRk2djW5+ISFLS6kTEEvhm1kIt7Ne7+3PR4iNmdk30+DXA0Ti2NVg6UCsieZLGbMI4ZukY8DjwqruvqXtoI3BPdPse4IVmtzVYOlArInmzPoVB6qgY1jEP+DTQZWad0bIHgdXA02b2GeDnwJ0xbGtQdKBWRPImjXP4Nh347v4PgPXx8E3Nrn+oNLoXkbxaXuliZfuMxNZfuG/aanQvInn17R3JtnUKF/giInl1IeG+TqECX+fMERHpW6ECX1MxRSTvkjy3TmECXwdrRaQIHt64J7F1FybwdbBWRIrgxOlzia27MIEvIiL9U+CLiJREIQJf/XsRkYEVIvDVvxcRGVghAl9EpEiSmpqpwBcRyZhlz+1OZL25D3x9u1ZEiuZ0Qtc9zH3gf2fHm6FLEBHJhdwH/nlP4yzSIiL5l/vAFxGRwVHgi4iUhAJfRKQkFPgiIiWhwBcRKYlcB36SFwoQESmaXAf+o99/PXQJIiKxu3JMSyLrzXXgV0+cDl2CiEjsVnz8+kTWm3jgm9ktZva6me0zs6VJb09EJO/aZ09MZL2JBr6ZjQT+O/AR4DrgU2Z2XZLbFBGRxpIe4d8I7HP3N9z9LPAUsDDhbYqISANJB/5EoP7sZoeiZSIikrLgB23NbLGZ7TSznceOHRvSayeOuzyhqkREiifpwK8C19bdnxQtu8jd17p7m7u3tba2DmnlX/7w+5qvUEQkQ0ZYgutObtUA/ASYbmZTzWw0cBewMa6VJ3UkW0QklD+cMzmxdY9KbM2Au3eb2eeB7wMjgW+5+54ktykikmcr22cktu5EAx/A3b8HfC/p7YiISP+CH7QVEZF0KPBFRDIiqXPo9FDgi4hkRFLn0OmR+8AfaQnOYRIRSVHSMw9zH/ifmnPtwE8SEcm40SOTH7zmPvCTnMIkIpKWr3/i/YlvI/eBLyJSBGl8kbQQgZ/0kW0RkSSNaUknigsR+Ekf2RYRSdLXbp+ZynYKEfjtsycy4YrRocsQERmWtM4LVojAB9jx0PzQJYiIDNnY0SNT21ZhAh9g3rTxoUsQERmSVbelN9OwUIG//rMfCF2CiMigjR5pqZ7mvVCBDxrli0h+pDH3vl7hAn/9Zz/AKJ1tQUQybqSlfxGnwgU+wL6/WBC6BBGRfn3jzlmpb7OQgQ9w99zkLhMmItKMedPGB7lEa2EDf2X7DN5zWXrTnUREBmPCFaODTTApbOAD7P7KLerni0imhPzOUKEDH2r9/H+TwmlHRUQGErrVXPjAB3ht1UfV3hGRoKZfPTb46dxLEfhQa+9ojr6IhDDhitFsue/3Q5dRnsCH2hz9A6sXaLQvIqmZfvXYzJzrq1SB32P3V24J3ksTkeJ77JOzMjGy79FU4JvZo2b2mpntNrPnzWxc3WPLzGyfmb1uZh9uutKYrWyfwYHVCziwegHTrx4buhwRKZD3XDaSA6sXBJlr359RTb5+C7DM3bvN7BFgGfCAmV0H3AVcD/wG8EMz+213P9/k9hJR/wk8Z9UWjpw8G64YEcm16VePzdSovl5Tge/uP6i7ux34RHR7IfCUu58BfmZm+4AbgW3NbC8N9b22Reu2sXX/8YDViEiezJs2PtNn7W12hF/vT4AN0e2J1D4AehyKluVK7/9xyytdfGfHm5x3D1SRiGTVY5+clbkWTm8DBr6Z/RD49QYPPeTuL0TPeQjoBtYPtQAzWwwsBpg8OdsHUle2z2g4j7bSUeWh57s4dTaTHSsRSVCWWzi9DRj47n5zf4+b2R8BHwNucr849K0C19Y9bVK0rNH61wJrAdra2nI5dG6fPfFdn+z6EBAptpYR8Ogd2R/V12uqpWNmtwD3A7/n7u/UPbQR+LaZraF20HY68I/NbCtv9CEgUkwjgDU5aN800mwP/2+Ay4AtZgaw3d0/5+57zOxp4BVqrZ57szpDJ02NPgSgdmxg/faD5PLPG5GSyOOIvjfzDB2AbGtr8507d4YuIyj9FSCSLXkIejPb5e5tAz0vzlk6EoPefwXoA0AkjDwE/VAp8DOurzaQPghEkjGmZQRfu31moYK+hwI/p3p/EOg4gMjwFTnk66mHX1DLK108uf1g6DJEMsmARXMnBz8/fVwG28NX4JeA2j8itatNFSXge9NBW7mo0YHgB57dzZnuCwGrEknWlWNaWPHx6wvfphkKBX4JaSaQFMnY0SNZddsMBfsgKPBFB4Al08pyQDUN6uHLgPQXgMRt3OUtPHyr2i1xUQ9fYtOoBfTo91/n/504za9e3sK/numm+0J2Bg4Sr6yf410GT4EvQ9bXl8FA00GLSBcBKg4FvsSq9zUDNCNIJDsU+JKoRgeE9ReASBg6aCtBaUZQPqiPn206aCu50NdlI3vMX/Mie4+eSrEiaUR9/GJQ4Eum9b5WqD4ARIZPgS+5Uv8BoOMB6ap0VDVvPufUw5fC0BfEkjXu8hY6V3wodBnSgHr4Ujq6cHyyTpw+F7oEaZICXwqt/kOg0lHlwed28845fSdAykmBL6XRO/zvf+Zlzp7PTktTJGkKfCml3uF/34ZONO6XohsRugCR0NpnT+SN1Qt47JOzGDt6ZOhyMuvKMS2hS5AmxRL4ZvYlM3Mzuyq6b2b2X81sn5ntNrMb4tiOSJLaZ09kz1dv4cDqBcybNj50OZmz4uPXhy5BmtR0S8fMrgU+BNRPiP4IMD36mQN8M/pXJBd6TiNQ6ajyxQ2dOvUDaA5+AcQxwv8r4H645HdiIfC/vGY7MM7MrolhWyKpap89kZ9F7Z4ya1HztxCa+t9oZguBqru/3OuhicCbdfcPRctEcql99kQOrF7A3XMnY6GLCeDRO2aFLkFiMGBLx8x+CPx6g4ceAh6k1s4ZNjNbDCwGmDx5cjOrEklc/cneFq3bVoqTio0aYWrnFMSAge/uNzdabmYzgKnAy2YGMAl4ycxuBKrAtXVPnxQta7T+tcBaqJ1aYSjFi4TU0+efsnRT4EqS9Zd3vD90CRKTYbd03L3L3a929ynuPoVa2+YGd38L2Aj8x2i2zlzgX9z9cDwli2RLT6uniO6eO1mj+wJJ6lDM94A3gH3AOuA/J7QdkUxY2T6jcNM5500b3++1CiR/YvumbTTK77ntwL1xrVskL3raPFOXbsr1VM7pV4/VFa4KSJOtRBKQ56mc068e+64Lz0gxKPBFEtIzlXPCFaNDlzJod8+drLAvMAW+SMJ2PDQ/8wd1500bz4HVC9SzLzgFvkgKeg7qZi34RwCPfXKW+vUloUscigQQ+nq84y5v4eFbr9eUy4IY7CUOFfgiAaV5IZbLW0bwF7fPVMgXkK5pK5ID9RdiSeJUDWNaRvA1hbxEFPgiGdG7jz6ca/CqVSP9UeCLZFT96F8kDpqlIyJSEgp8EZGSUOCLiJSEAl9EpCQU+CIiJZGpL16Z2THg5zGu8irgn2NcX9LyVi+o5jTkrV7IX815qxcurfk33b11oBdkKvDjZmY7B/Pts6zIW72gmtOQt3ohfzXnrV4YXs1q6YiIlIQCX0SkJIoe+GtDFzBEeasXVHMa8lYv5K/mvNULw6i50D18ERH5paKP8EVEJFKIwDezO8xsj5ldMLO2Xo8tM7N9Zva6mX24bvkt0bJ9ZrY0/aovqXGDmXVGPwfMrDNaPsXMTtc99rch66xnZg+bWbWuto/WPdZwn4dkZo+a2WtmttvMnjezcdHyzO5jyNb7tBEzu9bMfmxmr0S/g1+Ilvf5/siC6PesK6ptZ7RsvJltMbO90b9Xhq6zh5m9r25fdprZ22a2ZMj72d1z/wP8DvA+4EWgrW75dcDLwGXAVGA/MDL62Q/8FjA6es51of87opq/Afx5dHsK8NPQNfVR58PAnzVY3nCfZ6DeDwGjotuPAI/kYB9n9n1aV+M1wA3R7SuAf4reAw3fH1n5AQ4AV/Va9nVgaXR7ac97JGs/0fviLeA3h7qfCzHCd/dX3f31Bg8tBJ5y9zPu/jNgH3Bj9LPP3d9w97PAU9FzgzIzA+4EvhO6lib0tc+DcvcfuHt3dHc7MClkPYOUyfdpPXc/7O4vRbdPAq8CeT2n80Lgiej2E0B7uFL6dROw392H/CXVQgR+PyYCb9bdPxQt62t5aL8LHHH3vXXLpppZh5n9XzP73VCF9eHzUYvkW3V//mZ139b7E+Dv6+5ndR/nYV9eZGZTgNnAjmhRo/dHVjjwAzPbZWaLo2UT3P1wdPstYEKY0gZ0F5cOCge9n3MT+Gb2QzP7aYOfTI14+jLI+j/Fpf8jDwOT3X02cB/wbTN7T0Zq/iYwDZgV1fmNtOrqy2D2sZk9BHQD66NFQfdxUZjZrwDPAkvc/W0y+P7o5d+7+w3AR4B7zeyD9Q96rXeSuSmMZjYauBX4brRoSPs5N1e8cvebh/GyKnBt3f1J0TL6WZ6Igeo3s1HA7cC/q3vNGeBMdHuXme0HfhtI5Urvg93nZrYO+Lvobn/7PFGD2Md/BHwMuCn6hQ6+jwcQbF8OhZm1UAv79e7+HIC7H6l7vP79kQnuXo3+PWpmz1Nrnx0xs2vc/bCZXQMcDVpkYx8BXurZv0Pdz7kZ4Q/TRuAuM7vMzKYC04F/BH4CTDezqdEn5l3Rc0O6GXjN3Q/1LDCzVjMbGd3+LWr1vxGovktEvxA9bgN+Gt3ua58HZWa3APcDt7r7O3XLM7uPyeb79BLRcafHgVfdfU3d8r7eH8GZ2Vgzu6LnNrUD+j+ltm/viZ52D/BCmAr7dUkXYKj7OTcj/P6Y2W3AfwNagU1m1unuH3b3PWb2NPAKtT/j73X389FrPg98n9oR72+5+55A5ffo3ZcD+CDwVTM7B1wAPufux1OvrLGvm9ksan/2HgD+FKC/fR7Y31CbObSlllFsd/fPkeF97O7dGXyf9jYP+DTQZdF0YuBB4FON3h8ZMQF4PnofjAK+7e6bzewnwNNm9hlqZ+29M2CN7xJ9OM3n0n3Z8Pewz3VEf9mKiEjBFb2lIyIiEQW+iEhJKPBFREpCgS8iUhIKfBGRklDgi4iUhAJfRKQkFPgiIiXx/wGJvr2UMJkwPgAAAABJRU5ErkJggg==\n", 448 | "text/plain": [ 449 | "
" 450 | ] 451 | }, 452 | "metadata": { 453 | "needs_background": "light" 454 | }, 455 | "output_type": "display_data" 456 | } 457 | ], 458 | "source": [ 459 | "\n", 460 | "plt.scatter(vertices[:,1],vertices[:,2])" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": 1, 466 | "metadata": {}, 467 | "outputs": [ 468 | { 469 | "ename": "NameError", 470 | "evalue": "name 'intensity' is not defined", 471 | "output_type": "error", 472 | "traceback": [ 473 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 474 | "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", 475 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mintensity\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 476 | "\u001b[0;31mNameError\u001b[0m: name 'intensity' is not defined" 477 | ] 478 | } 479 | ], 480 | "source": [ 481 | "intensity" 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": null, 487 | "metadata": { 488 | "collapsed": true 489 | }, 490 | "outputs": [], 491 | "source": [] 492 | } 493 | ], 494 | "metadata": { 495 | "kernelspec": { 496 | "display_name": "padl", 497 | "language": "python", 498 | "name": "padl" 499 | }, 500 | "language_info": { 501 | "codemirror_mode": { 502 | "name": "ipython", 503 | "version": 3 504 | }, 505 | "file_extension": ".py", 506 | "mimetype": "text/x-python", 507 | "name": "python", 508 | "nbconvert_exporter": "python", 509 | "pygments_lexer": "ipython3", 510 | "version": "3.7.4" 511 | } 512 | }, 513 | "nbformat": 4, 514 | "nbformat_minor": 2 515 | } 516 | -------------------------------------------------------------------------------- /examples/script_matplotlib.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 3 | 4 | from matplotlib_surface_plotting import plot_surf 5 | import nibabel as nb 6 | import numpy as np 7 | 8 | vertices, faces=nb.freesurfer.io.read_geometry('../data/lh.inflated') 9 | overlay = nb.freesurfer.io.read_morph_data('../data/lh.thickness') 10 | 11 | #optional masking of medial wall 12 | cortex=nb.freesurfer.io.read_label('../data/lh.cortex.label') 13 | mask=np.ones_like(overlay).astype(bool) 14 | mask[cortex]=0 15 | overlay[mask]=np.min(overlay) 16 | 17 | plot_surf( vertices, faces, overlay, rotate=[90,270], filename='demo_plot.png', 18 | vmax = np.max(overlay[cortex]),vmin=np.min(overlay[cortex]),mask=mask, 19 | pvals=np.ones_like(overlay), cmap_label='thickness \n(mm)') 20 | -------------------------------------------------------------------------------- /figs/demo_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwagstyl/matplotlib_surface_plotting/9dcb13dbbd8d0ed765089486ef28dce225ebebb2/figs/demo_plot.png -------------------------------------------------------------------------------- /matplotlib_surface_plotting/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .matplotlib_surface_plotting import plot_surf -------------------------------------------------------------------------------- /matplotlib_surface_plotting/matplotlib_surface_plotting.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from matplotlib.collections import PolyCollection 4 | from matplotlib import cm 5 | 6 | def normalize_v3(arr): 7 | ''' Normalize a numpy array of 3 component vectors shape=(n,3) ''' 8 | lens = np.sqrt( arr[:,0]**2 + arr[:,1]**2 + arr[:,2]**2 ) 9 | arr[:,0] /= lens 10 | arr[:,1] /= lens 11 | arr[:,2] /= lens 12 | return arr 13 | 14 | def normal_vectors(vertices,faces): 15 | norm = np.zeros( vertices.shape, dtype=vertices.dtype ) 16 | tris = vertices[faces] 17 | n = np.cross( tris[::,1 ] - tris[::,0] , tris[::,2 ] - tris[::,0] ) 18 | n=normalize_v3(n) 19 | return n 20 | 21 | def vertex_normals(vertices,faces): 22 | norm = np.zeros( vertices.shape, dtype=vertices.dtype ) 23 | tris = vertices[faces] 24 | n = np.cross( tris[::,1 ] - tris[::,0] , tris[::,2 ] - tris[::,0] ) 25 | n=normalize_v3(n) 26 | norm[ faces[:,0] ] += n 27 | norm[ faces[:,1] ] += n 28 | norm[ faces[:,2] ] += n 29 | return normalize_v3(norm) 30 | 31 | 32 | def frustum(left, right, bottom, top, znear, zfar): 33 | M = np.zeros((4, 4), dtype=np.float32) 34 | M[0, 0] = +2.0 * znear / (right - left) 35 | M[1, 1] = +2.0 * znear / (top - bottom) 36 | M[2, 2] = -(zfar + znear) / (zfar - znear) 37 | M[0, 2] = (right + left) / (right - left) 38 | M[2, 1] = (top + bottom) / (top - bottom) 39 | M[2, 3] = -2.0 * znear * zfar / (zfar - znear) 40 | M[3, 2] = -1.0 41 | return M 42 | 43 | def perspective(fovy, aspect, znear, zfar): 44 | h = np.tan(0.5*np.radians(fovy)) * znear 45 | w = h * aspect 46 | return frustum(-w, w, -h, h, znear, zfar) 47 | 48 | def translate(x, y, z): 49 | return np.array([[1, 0, 0, x], [0, 1, 0, y], 50 | [0, 0, 1, z], [0, 0, 0, 1]], dtype=float) 51 | 52 | def xrotate(theta): 53 | t = np.pi * theta / 180 54 | c, s = np.cos(t), np.sin(t) 55 | return np.array([[1, 0, 0, 0], [0, c, -s, 0], 56 | [0, s, c, 0], [0, 0, 0, 1]], dtype=float) 57 | 58 | def yrotate(theta): 59 | t = np.pi * theta / 180 60 | c, s = np.cos(t), np.sin(t) 61 | return np.array([[ c, 0, s, 0], [ 0, 1, 0, 0], 62 | [-s, 0, c, 0], [ 0, 0, 0, 1]], dtype=float) 63 | 64 | def zrotate(theta): 65 | t = np.pi * theta / 180 66 | c, s = np.cos(t), np.sin(t) 67 | return np.array([[ c, -s, 0, 0], 68 | [ s, c, 0, 0], 69 | [0, 0, 1, 0], 70 | [ 0, 0, 0, 1]], dtype=float) 71 | 72 | def shading_intensity(vertices,faces, light = np.array([0,0,1]),shading=0.7): 73 | """shade calculation based on light source 74 | default is vertical light. 75 | shading controls amount of shading. 76 | Also saturates so top 20 % of vertices all have max intensity.""" 77 | face_normals=normal_vectors(vertices,faces) 78 | intensity = np.dot(face_normals, light) 79 | intensity[np.isnan(intensity)]=1 80 | shading = 0.7 81 | #top 20% all become fully coloured 82 | intensity = (1-shading)+shading*(intensity-np.min(intensity))/((np.percentile(intensity,80)-np.min(intensity))) 83 | #saturate 84 | intensity[intensity>1]=1 85 | 86 | return intensity 87 | 88 | 89 | def f7(seq): 90 | #returns uniques but in order to retain neighbour triangle relationship 91 | seen = set() 92 | seen_add = seen.add 93 | return [x for x in seq if not (x in seen or seen_add(x))]; 94 | 95 | 96 | def get_ring_of_neighbours(island, neighbours, vertex_indices=None, ordered=False): 97 | """Calculate ring of neighbouring vertices for an island of cortex 98 | If ordered, then vertices will be returned in connected order""" 99 | if not vertex_indices: 100 | vertex_indices=np.arange(len(island)) 101 | if not ordered: 102 | 103 | neighbours_island = neighbours[island] 104 | unfiltered_neighbours = [] 105 | for n in neighbours_island: 106 | unfiltered_neighbours.extend(n) 107 | unique_neighbours = np.setdiff1d(np.unique(unfiltered_neighbours), vertex_indices[island]) 108 | return unique_neighbours 109 | 110 | def get_neighbours_from_tris(tris, label=None): 111 | """Get surface neighbours from tris 112 | Input: tris 113 | Returns Nested list. Each list corresponds 114 | to the ordered neighbours for the given vertex""" 115 | n_vert=np.max(tris+1) 116 | neighbours=[[] for i in range(n_vert)] 117 | for tri in tris: 118 | neighbours[tri[0]].extend([tri[1],tri[2]]) 119 | neighbours[tri[2]].extend([tri[0],tri[1]]) 120 | neighbours[tri[1]].extend([tri[2],tri[0]]) 121 | #Get unique neighbours 122 | for k in range(len(neighbours)): 123 | if label is not None: 124 | neighbours[k] = set(neighbours[k]).intersection(label) 125 | else : 126 | neighbours[k]=f7(neighbours[k]) 127 | return np.array(neighbours,dtype=object) 128 | 129 | def mask_colours(colours,triangles,mask,mask_colour=None): 130 | """grey out mask""" 131 | if mask is not None: 132 | if mask_colour is None: 133 | mask_colour = np.array([0.86,0.86,0.86,1]) 134 | verts_masked = mask[triangles].any(axis=1) 135 | colours[verts_masked,:] = mask_colour 136 | return colours 137 | 138 | def adjust_colours_pvals(colours, pvals,triangles,mask=None,mask_colour=None, 139 | border_colour = np.array([1.0,0,0,1])): 140 | """red ring around clusters and greying out non-significant vertices""" 141 | colours=mask_colours(colours,triangles,mask,mask_colour) 142 | neighbours=get_neighbours_from_tris(triangles) 143 | ring=get_ring_of_neighbours(pvals<0.05,neighbours) 144 | if len(ring)>0: 145 | ring_label = np.zeros(len(neighbours)).astype(bool) 146 | ring_label[ring]=1 147 | ring=get_ring_of_neighbours(ring_label,neighbours) 148 | ring_label[ring]=1 149 | colours[ring_label[triangles].any(axis=1),:] = border_colour 150 | grey_out=pvals<0.05 151 | verts_grey_out= grey_out[triangles].any(axis=1) 152 | colours[verts_grey_out,:] = (1.5*colours[verts_grey_out] + np.array([0.86,0.86,0.86,1]))/2.5 153 | return colours 154 | 155 | 156 | 157 | def add_parcellation_colours(colours,parcel,triangles,labels=None, 158 | mask=None,filled=False,mask_colour=None, neighbours=None): 159 | """delineate regions""" 160 | colours=mask_colours(colours,triangles,mask,mask_colour=mask_colour) 161 | #normalise rois and colors 162 | rois=list(set(parcel)) 163 | if 0 in rois: 164 | rois.remove(0) 165 | if labels is None : 166 | labels = dict(zip(rois, np.random.rand(len(rois),4))) 167 | #remove transparent rois 168 | #find vertices that delineate rois 169 | if filled: 170 | colours=np.zeros_like(colours) 171 | for l,label in enumerate(rois): 172 | colours[np.median(parcel[triangles],axis=1)==label]=labels[label] 173 | return colours 174 | if neighbours is None: 175 | neighbours=get_neighbours_from_tris(triangles) 176 | matrix_colored = np.zeros([len(triangles), len(rois)]) 177 | for l,label in enumerate(rois): 178 | ring=get_ring_of_neighbours(parcel!=label,neighbours) 179 | if len(ring)>0: 180 | ring_label = np.zeros(len(neighbours)).astype(bool) 181 | ring_label[ring]=1 182 | # ring=get_ring_of_neighbours(ring_label,neighbours) 183 | # ring_label[ring]=1 184 | # matrix_colored[:,l] = ring_label[triangles].sum(axis=1) 185 | matrix_colored[:,l] = np.median(ring_label[triangles],axis=1) #ring_label[triangles].sum(axis=1) 186 | #update colours with delineation 187 | maxis = [max(matrix_colored[i,:]) for i in range(0,len(colours))] 188 | colours = np.array([labels[rois[np.random.choice(np.where(matrix_colored[i,:] == maxi)[0])]] 189 | if maxi!=0 else colours[i] for i,maxi in enumerate(maxis)]) 190 | return colours 191 | 192 | 193 | def adjust_colours_alpha(colours,alpha): 194 | """grey out vertices according to scalar""" 195 | #rescale alpha to 0.2-1.0 196 | alpha_rescaled = 0.1+0.9*(alpha-np.min(alpha))/(np.max(alpha)-np.min(alpha)) 197 | colours = (alpha_rescaled*colours.T).T + ((1-alpha_rescaled)*np.array([0.86,0.86,0.86,1]).reshape(-1,1)).T 198 | colours = np.clip(colours, 0,1) 199 | return colours 200 | 201 | def frontback(T): 202 | """ 203 | Sort front and back facing triangles 204 | Parameters: 205 | ----------- 206 | T : (n,3) array 207 | Triangles to sort 208 | Returns: 209 | -------- 210 | front and back facing triangles as (n1,3) and (n2,3) arrays (n1+n2=n) 211 | """ 212 | Z = (T[:,1,0]-T[:,0,0])*(T[:,1,1]+T[:,0,1]) + \ 213 | (T[:,2,0]-T[:,1,0])*(T[:,2,1]+T[:,1,1]) + \ 214 | (T[:,0,0]-T[:,2,0])*(T[:,0,1]+T[:,2,1]) 215 | return Z < 0, Z >= 0 216 | 217 | def normalized(a, axis=-1, order=2): 218 | l2 = np.atleast_1d(np.linalg.norm(a, order, axis)) 219 | l2[l2==0] = 1 220 | return a / np.expand_dims(l2, axis) 221 | 222 | 223 | def plot_surf(vertices, faces,overlay, rotate=[90,270], cmap='viridis', filename='plot.png', label=False, 224 | vmax=None, vmin=None, x_rotate=270, pvals=None, colorbar=True, cmap_label='value', 225 | title=None, mask=None, base_size=6, arrows=None,arrow_subset=None,arrow_size=0.5, 226 | arrow_colours = None,arrow_head=0.05,arrow_width=0.001, 227 | mask_colour=None,transparency=1,show_back=False,border_colour = np.array([1,0,0,1]), 228 | alpha_colour = None,flat_map=False, z_rotate=0,neighbours=None, 229 | parcel=None, parcel_cmap=None,filled_parcels=False,return_ax=False): 230 | """ This function plot mesh surface with a given overlay. 231 | Features available : display in flat surface, display parcellation on top, display gradients arrows on top 232 | 233 | 234 | Parameters: 235 | ---------- 236 | vertices : numpy array 237 | vertex locations 238 | faces : numpy array 239 | triangles of vertex indices definings faces 240 | overlay : numpy array 241 | array to be plotted 242 | rotate : tuple, optional 243 | rotation angle for lateral on lh, and medial 244 | cmap : string, optional 245 | matplotlib colormap 246 | filename : string, optional 247 | name of the figure to save 248 | label : bool, optional 249 | colours smoothed (mean) or median if label 250 | vmin, vmax : float, optional 251 | min and max value for display intensity 252 | x_rotate : int, optional 253 | 254 | pvals : bool, optional 255 | 256 | colorbar : bool, optional 257 | display or not colorbar 258 | cmap_label : string, optional 259 | label of the colorbar 260 | title : string, optional 261 | title of the figure 262 | mask : numpy array, optional 263 | vector to mask part of the surface 264 | base_size : int, optional 265 | 266 | arrows : numpy array, optional 267 | dipsplay arrows in the directions of gradients on top of the surface 268 | arrow_subset : numpy array, optional 269 | vector containing at which vertices display an arrow 270 | arrow_size : float, optional 271 | size of the arrow 272 | arrow_colours: 273 | alpha_colour : float, optional 274 | value to play with transparency of the overlay 275 | flat_map : bool, optional 276 | display on flat map 277 | z_rotate : int, optional 278 | transparency : float, optional 279 | value between 0-1 to play with mesh transparency 280 | show_back : bool, optional 281 | display or hide the faces in the back of the mesh (z<0) 282 | parcel : numpy array, optional 283 | delineate rois on top of the surface 284 | parcel_cmap : dictionary, optional 285 | dic containing labels and colors associated for the parcellation 286 | filled_parcels: fill the parcel colours 287 | neighbours : provided neighbours in case faces is only a subset of all vertices 288 | 289 | """ 290 | vertices=vertices.astype(np.float32) 291 | F=faces.astype(int) 292 | vertices = (vertices-(vertices.max(0)+vertices.min(0))/2)/max(vertices.max(0)-vertices.min(0)) 293 | if not isinstance(rotate,list): 294 | rotate=[rotate] 295 | if not isinstance(overlay,list): 296 | overlays=[overlay] 297 | else: 298 | overlays=overlay 299 | if parcel is not None: 300 | if parcel.sum() == 0: 301 | parcel = None 302 | if flat_map: 303 | z_rotate=90 304 | rotate=[90] 305 | intensity = np.ones(len(F)) 306 | else: 307 | #change light source if z is rotate 308 | light = np.array([0,0,1,1]) @ yrotate(z_rotate) 309 | intensity=shading_intensity(vertices, F, light=light[:3],shading=0.7) 310 | #make figure dependent on rotations 311 | 312 | fig = plt.figure(figsize=(base_size*len(rotate)+colorbar*(base_size-2), 313 | (base_size-1)*len(overlays))) 314 | if title is not None: 315 | plt.title(title, fontsize=25) 316 | plt.axis('off') 317 | for k,overlay in enumerate(overlays): 318 | #colours smoothed (mean) or median if label 319 | if label: 320 | colours = np.median(overlay[F],axis=1) 321 | else: 322 | colours = np.mean(overlay[F],axis=1) 323 | if vmax is not None: 324 | colours = (colours - vmin)/(vmax-vmin) 325 | colours = np.clip(colours,0,1) 326 | else: 327 | vmax = colours.max() 328 | vmin = colours.min() 329 | colours = (colours - colours.min())/(colours.max()-colours.min()) 330 | C = plt.get_cmap(cmap)(colours) 331 | if alpha_colour is not None: 332 | C = adjust_colours_alpha(C,np.mean(alpha_colour[F],axis=1)) 333 | if pvals is not None: 334 | C = adjust_colours_pvals(C,pvals,F,mask,mask_colour=mask_colour, 335 | border_colour=border_colour) 336 | elif mask is not None: 337 | C = mask_colours(C,F,mask,mask_colour=mask_colour) 338 | if parcel is not None : 339 | C = add_parcellation_colours(C,parcel,F,parcel_cmap, 340 | mask,mask_colour=mask_colour, 341 | filled=filled_parcels, neighbours=neighbours) 342 | 343 | #adjust intensity based on light source here 344 | C[:,0] *= intensity 345 | C[:,1] *= intensity 346 | C[:,2] *= intensity 347 | 348 | collection = PolyCollection([], closed=True, linewidth=0,antialiased=False, facecolor=C, cmap=cmap) 349 | for i,view in enumerate(rotate): 350 | MVP = perspective(25,1,1,100) @ translate(0,0,-3) @ yrotate(view) @ zrotate(z_rotate) @ xrotate(x_rotate) @ zrotate(270*flat_map) 351 | #translate coordinates based on viewing position 352 | V = np.c_[vertices, np.ones(len(vertices))] @ MVP.T 353 | 354 | V /= V[:,3].reshape(-1,1) 355 | center = np.array([0, 0, 0, 1]) @ MVP.T; 356 | center /= center[3]; 357 | # add vertex positions to A_dir before transforming them 358 | if arrows is not None: 359 | #calculate arrow position + small shift in surface normal direction 360 | vertex_normal_orig = vertex_normals(vertices,faces) 361 | A_base = np.c_[vertices+vertex_normal_orig*0.01, np.ones(len(vertices))] @ MVP.T 362 | A_base /= A_base[:,3].reshape(-1,1) 363 | 364 | #calculate arrow direction 365 | A_dir = np.copy(arrows) 366 | #normalise arrow size 367 | max_arrow = np.max(np.linalg.norm(arrows,axis=1)) 368 | A_dir = arrow_size*A_dir/max_arrow 369 | A_dir = np.c_[A_dir, np.ones(len(A_dir))] @ MVP.T 370 | A_dir /= A_dir[:,3].reshape(-1,1) 371 | # A_dir *= 0.1; 372 | 373 | V = V[F] 374 | 375 | #triangle coordinates 376 | T = V[:,:,:2] 377 | #get Z values for ordering triangle plotting 378 | Z = -V[:,:,2].mean(axis=1) 379 | #sort the triangles based on their z coordinate. If front/back views then need to sort a different axis 380 | front, back = frontback(T) 381 | if show_back == False: 382 | T=T[front] 383 | s_C = C[front] 384 | Z = Z[front] 385 | else: 386 | s_C = C 387 | I = np.argsort(Z) 388 | T, s_C = T[I,:], s_C[I,:] 389 | ax = fig.add_subplot(len(overlays),len(rotate)+1,2*k+i+1, xlim=[-.98,+.98], ylim=[-.98,+.98],aspect=1, frameon=False, 390 | xticks=[], yticks=[]) 391 | collection = PolyCollection(T, closed=True, linewidth=0,antialiased=False, facecolor=s_C, cmap=cmap) 392 | collection.set_alpha(transparency) 393 | ax.add_collection(collection) 394 | #add arrows to image 395 | if arrows is not None: 396 | front_arrows = F[front].ravel() 397 | for arrow_index,i in enumerate(arrow_subset): 398 | if i in front_arrows and A_base[i,2] < center[2] + 0.01: 399 | arrow_colour = 'k' 400 | if arrow_colours is not None: 401 | arrow_colour = arrow_colours[arrow_index] 402 | #if length of arrows corresponds perfectly with coordinates 403 | # assume 1:1 matching 404 | if len(A_dir) == len(A_base): 405 | direction = A_dir[i] 406 | #otherwise, assume it is a custom list matching the 407 | elif len(A_dir) == len(arrow_subset): 408 | direction = A_dir[arrow_index] 409 | half = direction * 0.5 410 | 411 | ax.arrow(A_base[i,0] - half[0], 412 | A_base[i,1] - half[1], 413 | direction[0], direction[1], 414 | head_width=arrow_head,width =arrow_width, 415 | color = arrow_colour) 416 | # ax.arrow(A_base[idx,0], A_base[idx,1], A_dir[i,0], A_dir[i,1], head_width=0.01) 417 | plt.subplots_adjust(left =0 , right =1, top=1, bottom=0,wspace=0, hspace=0) 418 | 419 | if colorbar: 420 | l=0.7 421 | if len(rotate)==1: 422 | l=0.5 423 | cbar_size= [l, 0.3, 0.03, 0.38] 424 | cbar = fig.colorbar(collection, 425 | ticks=[0,0.5, 1], 426 | cax = fig.add_axes(cbar_size), 427 | ) 428 | cbar.ax.set_yticklabels([np.round(vmin,decimals=2), np.round(np.mean([vmin,vmax]),decimals=2), 429 | np.round(vmax,decimals=2)]) 430 | cbar.ax.tick_params(labelsize=25) 431 | cbar.ax.set_title(cmap_label, fontsize=25, pad = 30) 432 | if filename is not None: 433 | fig.savefig(filename,bbox_inches = 'tight',pad_inches=0,transparent=True) 434 | if return_ax: 435 | return fig,ax,MVP 436 | return 437 | 438 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open("README.md", "r", encoding="utf-8") as fh: 4 | long_description = fh.read() 5 | 6 | 7 | setup(name='matplotlib_surface_plotting', 8 | version='0.12', 9 | packages=find_packages(), 10 | install_requires=['nibabel', 11 | 'matplotlib>=3.3.2'], 12 | package_dir={'matplotlib_surface_plotting':'matplotlib_surface_plotting'}, 13 | url="https://github.com/kwagstyl/matplotlib_surface_plotting", 14 | description="Brain mesh plotting in matplotlib", 15 | long_description=long_description, 16 | long_description_content_type="text/markdown", 17 | ) 18 | -------------------------------------------------------------------------------- /test/test-pip.py: -------------------------------------------------------------------------------- 1 | import matplotlib_surface_plotting 2 | 3 | print("imported!") --------------------------------------------------------------------------------