Coverage for src / thunderfish / fishshapes.py: 99%
307 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-15 17:50 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-15 17:50 +0000
1"""Manipulate and plot fish outlines.
3## Fish shapes
5Fish shapes are dictionaries with the keys 'body', 'fin0', 'fin1' ...,
6and 'eye'. The values are 2D arrays with x-y coordinates (first
7dimension is points, second dimension coordinates) of the respective
8pathes.
10All fish shapes of this module are accessible via these dictionaries:
12- `fish_shapes`: dictionary holding all electric fish shapes.
13- `fish_top_shapes`: dictionary holding electric fish shapes viewed from top.
14- `fish_side_shapes`: dictionary holding electric fish shapes viewed from the side.
16These are the shapes of various fish species:
18- `Alepto_top`: *Apteronotus leptorhynchus* viewed from top.
19- `Alepto_male_side`: Male *Apteronotus leptorhynchus* viewed from the side.
20- `Eigenmannia_top`: *Eigenmannia virescens* viewed from top.
21- `Eigenmannia_side`: *Eigenmannia virescens* viewed from the side.
22- `Gpetersii_top`: *Ganthonemus petersii* viewed from top.
23- `Gpetersii_side`: *Ganthonemus petersii* viewed from the side.
25Helper function for selecting a particular fish shape:
27- `fish_shape()`: get a dictinary containing shapes of a fish.
29## Plotting
31- `plot_fish()`: plot body, fins and eye of an electric fish.
32- `plot_object()`: plot circular object.
33- `plot_fishfinder()`: plot a fishfinder with electrodes and wires.
34- `plot_pathes()`: plot pathes.
36## Fish surface and normals from shapes
38- `fish_surface()`: generate meshgrid of one side of the fish from shape.
39- `surface_normals()`: normal vectors on a surface.
41## General path manipulations
43You may use these functions to extract and fine tune pathes from SVG
44files in order to assemble fish shapes for this module. See
45`export_fish_demo()` for a use case.
47- `extract_path()`: convert SVG pathes to numpy arrays with path coordinates.
48- `bbox_pathes()`: common bounding box of pathes.
49- `translate_pathes()`: translate pathes in place.
50- `center_pathes()`: translate pathes to their common origin in place.
51- `rotate_pathes()`: rotate pathes in place.
52- `flipy_pathes()`: flip pathes in y-direction in place.
53- `flipx_pathes()`: flip pathes in x-direction in place.
54- `export_path()`: print coordinates of path for import as numpy array.
55- `mirror_path()`: complete path of half a fish outline by appending the mirrored path.
56- `normalize_path()`: normalize fish outline to unit length.
57- `bend_path()`: bend and scale a path.
59## Exporting fish outlines from pathes
61- `export_fish()`: serialize coordinates of fish outlines as a dictionary.
62- `export_fish_demo()`: code demonstrating how to export fish outlines from SVG file.
64"""
66import numpy as np
67import matplotlib as mpl
68import matplotlib.pyplot as plt
69import matplotlib.transforms as mpt
71from matplotlib.path import Path
72from matplotlib.patches import PathPatch, Circle, Rectangle
75Alepto_top = dict(body=np.array([
76 [-5.00000000e-01, 0.00000000e+00], [-4.99802704e-01, 1.23222860e-03],
77 [-4.95374557e-01, 2.57983066e-03], [-4.84420392e-01, 3.29085947e-03],
78 [-4.72487909e-01, 4.03497963e-03], [-4.13995354e-01, 4.39637211e-03],
79 [-3.90529212e-01, 5.14049228e-03], [-3.67089631e-01, 5.88461244e-03],
80 [-3.43596916e-01, 6.65006783e-03], [-3.20104187e-01, 7.39418800e-03],
81 [-2.97063253e-01, 8.11708180e-03], [-2.79461930e-01, 8.49142780e-03],
82 [-2.61664711e-01, 9.24382081e-03], [-2.38198570e-01, 1.03918950e-02],
83 [-2.14732428e-01, 1.14974077e-02], [-1.91239699e-01, 1.26242555e-02],
84 [-1.67773558e-01, 1.37511034e-02], [-1.44307403e-01, 1.52605701e-02],
85 [-1.09307508e-01, 1.71314946e-02], [-8.58413531e-02, 1.86197349e-02],
86 [-6.23486380e-02, 2.01079753e-02], [-3.88824966e-02, 2.12348231e-02],
87 [-1.54429155e-02, 2.19789433e-02], [1.95835670e-02, 2.31057367e-02],
88 [4.30231346e-02, 2.38498569e-02], [6.65424230e-02, 2.49767047e-02],
89 [8.99820050e-02, 2.57421601e-02], [1.13448146e-01, 2.64862803e-02],
90 [1.36914287e-01, 2.91013032e-02], [1.60380442e-01, 3.28431304e-02],
91 [1.83873157e-01, 3.43101008e-02], [2.06914105e-01, 3.54369487e-02],
92 [2.18819919e-01, 3.58196764e-02], [2.42339207e-01, 3.65850229e-02],
93 [2.72903364e-01, 3.57933339e-02], [2.75411585e-01, 3.56061065e-02],
94 [2.74126982e-01, 3.73081344e-02], [2.60251756e-01, 4.14908387e-02],
95 [2.47930096e-01, 4.96419915e-02], [2.39119358e-01, 6.08413919e-02],
96 [2.39547832e-01, 7.56059835e-02], [2.44279733e-01, 7.95534778e-02],
97 [2.54298155e-01, 7.66782524e-02], [2.69627591e-01, 6.28724285e-02],
98 [2.82177993e-01, 4.80249888e-02], [2.88316671e-01, 3.79294791e-02],
99 [2.89271585e-01, 3.54368942e-02], [2.92213886e-01, 3.54205663e-02],
100 [3.01203973e-01, 3.58192954e-02], [3.12737740e-01, 4.10493520e-02],
101 [3.24670128e-01, 3.99438067e-02], [3.36177308e-01, 3.88170133e-02],
102 [3.48109696e-01, 3.76902090e-02], [3.71177217e-01, 3.54366112e-02],
103 [3.94643358e-01, 3.24601523e-02], [4.18136073e-01, 2.91010093e-02],
104 [4.41602228e-01, 2.61033022e-02], [4.65041796e-01, 2.27229002e-02],
105 [4.77000757e-01, 2.01078773e-02], [4.88938465e-01, 1.57516176e-02],
106 [4.97051671e-01, 9.88149348e-03], [5.00000000e-01, 4.58499286e-03],
107 [5.00000000e-01, -4.58499286e-03], [4.97051671e-01, -9.88149348e-03],
108 [4.88938465e-01, -1.57516176e-02], [4.77000757e-01, -2.01078773e-02],
109 [4.65041796e-01, -2.27229002e-02], [4.41602228e-01, -2.61033022e-02],
110 [4.18136073e-01, -2.91010093e-02], [3.94643358e-01, -3.24601523e-02],
111 [3.71177217e-01, -3.54366112e-02], [3.48109696e-01, -3.76902090e-02],
112 [3.36177308e-01, -3.88170133e-02], [3.24670128e-01, -3.99438067e-02],
113 [3.12737740e-01, -4.10493520e-02], [3.01203973e-01, -3.58192954e-02],
114 [2.92213886e-01, -3.54205663e-02], [2.89271585e-01, -3.54368942e-02],
115 [2.88316671e-01, -3.79294791e-02], [2.82177993e-01, -4.80249888e-02],
116 [2.69627591e-01, -6.28724285e-02], [2.54298155e-01, -7.66782524e-02],
117 [2.44279733e-01, -7.95534778e-02], [2.39547832e-01, -7.56059835e-02],
118 [2.39119358e-01, -6.08413919e-02], [2.47930096e-01, -4.96419915e-02],
119 [2.60251756e-01, -4.14908387e-02], [2.74126982e-01, -3.73081344e-02],
120 [2.75411585e-01, -3.56061065e-02], [2.72903364e-01, -3.57933339e-02],
121 [2.42339207e-01, -3.65850229e-02], [2.18819919e-01, -3.58196764e-02],
122 [2.06914105e-01, -3.54369487e-02], [1.83873157e-01, -3.43101008e-02],
123 [1.60380442e-01, -3.28431304e-02], [1.36914287e-01, -2.91013032e-02],
124 [1.13448146e-01, -2.64862803e-02], [8.99820050e-02, -2.57421601e-02],
125 [6.65424230e-02, -2.49767047e-02], [4.30231346e-02, -2.38498569e-02],
126 [1.95835670e-02, -2.31057367e-02], [-1.54429155e-02, -2.19789433e-02],
127 [-3.88824966e-02, -2.12348231e-02], [-6.23486380e-02, -2.01079753e-02],
128 [-8.58413531e-02, -1.86197349e-02], [-1.09307508e-01, -1.71314946e-02],
129 [-1.44307403e-01, -1.52605701e-02], [-1.67773558e-01, -1.37511034e-02],
130 [-1.91239699e-01, -1.26242555e-02], [-2.14732428e-01, -1.14974077e-02],
131 [-2.38198570e-01, -1.03918950e-02], [-2.61664711e-01, -9.24382081e-03],
132 [-2.79461930e-01, -8.49142780e-03], [-2.97063253e-01, -8.11708180e-03],
133 [-3.20104187e-01, -7.39418800e-03], [-3.43596916e-01, -6.65006783e-03],
134 [-3.67089631e-01, -5.88461244e-03], [-3.90529212e-01, -5.14049228e-03],
135 [-4.13995354e-01, -4.39637211e-03], [-4.72487909e-01, -4.03497963e-03],
136 [-4.84420392e-01, -3.29085947e-03], [-4.95374557e-01, -2.57983066e-03],
137 [-4.99802704e-01, -1.23222860e-03], [-5.00000000e-01, -0.00000000e+00],]))
138"""Outline of an *Apteronotus leptorhynchus* viewed from top, modified from Krahe 2004."""
140Alepto_male_side = dict(body=np.array([
141 [2.80332097e-01, 5.51361973e-02], [2.41127905e-01, 5.93460338e-02],
142 [1.91463866e-01, 6.22667811e-02], [1.37379023e-01, 6.17716006e-02],
143 [6.91234340e-02, 5.72953633e-02], [-1.36051588e-02, 4.74838393e-02],
144 [-7.55221954e-02, 3.64211032e-02], [-1.60157310e-01, 2.45651115e-02],
145 [-2.32035003e-01, 1.55421483e-02], [-2.99079447e-01, 9.70960800e-03],
146 [-3.62251791e-01, 6.27265707e-03], [-4.20527920e-01, 4.22449025e-03],
147 [-4.72735573e-01, 5.39606712e-03], [-4.80154179e-01, 5.86398206e-03],
148 [-4.92605065e-01, 1.01411700e-02], [-4.97402289e-01, 5.91543079e-03],
149 [-5.00000000e-01, -2.84973497e-03], [-4.97832769e-01, -1.17981289e-02],
150 [-4.93106950e-01, -1.43380199e-02], [-4.81164618e-01, -8.19215843e-03],
151 [-4.72578673e-01, -6.17623988e-03], [-4.45390092e-01, -5.96123217e-03],
152 [-3.74805165e-01, -9.05994885e-03], [-3.33716813e-01, -1.08317142e-02],
153 [-3.08099380e-01, -1.15017063e-02], [-2.82451613e-01, -1.30396176e-02],
154 [-2.34498580e-01, -2.21834040e-02], [-1.86892658e-01, -3.26728000e-02],
155 [-1.08738732e-01, -4.99024273e-02], [-3.50753879e-02, -5.94218882e-02],
156 [3.28767168e-02, -6.58397526e-02], [1.25319086e-01, -7.21513968e-02],
157 [1.99523049e-01, -7.99740378e-02], [2.37035792e-01, -8.44828747e-02],
158 [2.74475366e-01, -8.68964223e-02], [3.12742824e-01, -8.34038539e-02],
159 [3.36340505e-01, -7.82231053e-02], [3.55492327e-01, -7.21451373e-02],
160 [3.74670470e-01, -6.45564453e-02], [3.82920881e-01, -6.06824741e-02],
161 [3.84828678e-01, -5.92550189e-02], [3.86562866e-01, -5.99353293e-02],
162 [3.90753372e-01, -6.01589140e-02], [4.03494946e-01, -5.90960625e-02],
163 [4.38474761e-01, -6.13270959e-02], [4.61389913e-01, -6.47960654e-02],
164 [4.77010163e-01, -6.86433853e-02], [4.84437594e-01, -6.89404377e-02],
165 [4.90842798e-01, -6.82840746e-02], [4.94567181e-01, -6.58050993e-02],
166 [4.95443985e-01, -6.30972916e-02], [4.94497789e-01, -6.10849673e-02],
167 [4.91729699e-01, -6.00016418e-02], [4.84298546e-01, -5.78808424e-02],
168 [4.93112897e-01, -5.45550751e-02], [4.97742360e-01, -5.12667865e-02],
169 [5.00000000e-01, -4.73196051e-02], [4.99521047e-01, -4.36153642e-02],
170 [4.96159278e-01, -3.87756472e-02], [4.86402575e-01, -3.18513601e-02],
171 [4.67134496e-01, -2.06920393e-02], [4.39218141e-01, -5.92866768e-03],
172 [4.25010402e-01, 4.45359743e-03], [4.14788070e-01, 1.39860522e-02],
173 [3.93656086e-01, 2.44160739e-02], [3.75679976e-01, 2.94323719e-02],
174 [3.61404254e-01, 3.69002336e-02], [3.37900061e-01, 4.40458301e-02],
175 [3.11463577e-01, 4.97553861e-02],]),
176 fin0=np.array([
177 [3.29593304e-01, -7.95912942e-02], [3.27561074e-01, -8.48367727e-02],
178 [3.08709726e-01, -9.90609655e-02], [2.80934315e-01, -1.08062137e-01],
179 [2.58017473e-01, -1.12878542e-01], [2.35142157e-01, -1.14467112e-01],
180 [2.18081531e-01, -1.12354592e-01], [1.98185626e-01, -1.10721292e-01],
181 [1.78099090e-01, -1.13640193e-01], [1.59752865e-01, -1.18762090e-01],
182 [1.40752841e-01, -1.20266781e-01], [1.27904629e-01, -1.17712356e-01],
183 [1.19134213e-01, -1.12284346e-01], [1.09580014e-01, -1.04436264e-01],
184 [8.20184710e-02, -9.60992771e-02], [5.05598670e-02, -9.57289587e-02],
185 [2.74790284e-02, -1.04021601e-01], [3.92704920e-03, -1.08834461e-01],
186 [-3.12710137e-02, -1.08965162e-01], [-5.88865488e-02, -1.03820945e-01],
187 [-7.82549598e-02, -9.45428978e-02], [-9.94601687e-02, -8.20174601e-02],
188 [-1.29941640e-01, -7.01658118e-02], [-1.58259295e-01, -6.73695625e-02],
189 [-1.86001442e-01, -7.01570717e-02], [-2.14339679e-01, -6.79007296e-02],
190 [-2.38708971e-01, -5.78982409e-02], [-2.55168178e-01, -4.41230328e-02],
191 [-2.71293058e-01, -3.28785160e-02], [-2.88416341e-01, -2.86291802e-02],
192 [-3.06103856e-01, -2.82461534e-02], [-3.22345146e-01, -2.47128040e-02],
193 [-3.38333410e-01, -1.44124470e-02], [-3.43264223e-01, -1.03691894e-02],
194 [-3.08609907e-01, -1.12571357e-02], [-2.86088545e-01, -1.25633719e-02],
195 [-2.59977440e-01, -1.65414204e-02], [-2.16119429e-01, -2.64072955e-02],
196 [-1.68443229e-01, -3.68996138e-02], [-1.12717944e-01, -4.88585839e-02],
197 [-7.07908982e-02, -5.51259999e-02], [-1.80906639e-02, -6.16068166e-02],
198 [2.75299392e-02, -6.53080983e-02], [7.71390030e-02, -6.85205021e-02],
199 [1.21071140e-01, -7.25104674e-02], [1.78723549e-01, -7.85286909e-02],
200 [2.32100395e-01, -8.40268652e-02], [2.74938812e-01, -8.74456073e-02],
201 [3.10041908e-01, -8.43007220e-02],]),
202 eye=np.array([0.4, 0.0, 0.01]))
203"""Outline of an *Apteronotus leptorhynchus* male viewed from the side."""
205Eigenmannia_top = dict(body=np.array([
206 [-5.00000000e-01, 0.00000000e+00], [-4.84515329e-01, 4.41536208e-03],
207 [-4.76913801e-01, 5.34924846e-03], [-3.94680346e-01, 8.25734868e-03],
208 [-2.74106007e-01, 8.94059314e-03], [-1.35145770e-01, 1.09559947e-02],
209 [2.36080412e-02, 1.40941342e-02], [1.36968804e-01, 1.51550643e-02],
210 [2.15041020e-01, 1.96734219e-02], [2.83582110e-01, 2.36895289e-02],
211 [3.20834553e-01, 2.63067663e-02], [3.46646908e-01, 2.77590937e-02],
212 [3.68462758e-01, 2.97229886e-02], [3.62525174e-01, 3.12766064e-02],
213 [3.57215426e-01, 3.25163153e-02], [3.51347983e-01, 3.44809486e-02],
214 [3.46108357e-01, 3.83290703e-02], [3.44207747e-01, 4.53621620e-02],
215 [3.46387987e-01, 5.39648157e-02], [3.54784122e-01, 6.69720204e-02],
216 [3.67470562e-01, 8.11691502e-02], [3.80987875e-01, 9.13148567e-02],
217 [3.90738756e-01, 9.39276818e-02], [3.95854520e-01, 9.06728175e-02],
218 [3.99717109e-01, 8.49081236e-02], [3.96997843e-01, 6.54750599e-02],
219 [3.89101023e-01, 4.11631100e-02], [3.86289062e-01, 3.71837960e-02],
220 [3.94553267e-01, 3.78052325e-02], [4.03373690e-01, 3.72181278e-02],
221 [4.20207675e-01, 3.56696607e-02], [4.37553246e-01, 3.46018748e-02],
222 [4.59139056e-01, 3.15068918e-02], [4.79811600e-01, 2.68634593e-02],
223 [4.92810472e-01, 1.97499259e-02], [4.98594784e-01, 1.11517021e-02],
224 [5.00000000e-01, 5.62393850e-03], [5.00000000e-01, -5.62393850e-03],
225 [4.98594784e-01, -1.11517021e-02], [4.92810472e-01, -1.97499259e-02],
226 [4.79811600e-01, -2.68634593e-02], [4.59139056e-01, -3.15068918e-02],
227 [4.37553246e-01, -3.46018748e-02], [4.20207675e-01, -3.56696607e-02],
228 [4.03373690e-01, -3.72181278e-02], [3.94553267e-01, -3.78052325e-02],
229 [3.86289062e-01, -3.71837960e-02], [3.89101023e-01, -4.11631100e-02],
230 [3.96997843e-01, -6.54750599e-02], [3.99717109e-01, -8.49081236e-02],
231 [3.95854520e-01, -9.06728175e-02], [3.90738756e-01, -9.39276818e-02],
232 [3.80987875e-01, -9.13148567e-02], [3.67470562e-01, -8.11691502e-02],
233 [3.54784122e-01, -6.69720204e-02], [3.46387987e-01, -5.39648157e-02],
234 [3.44207747e-01, -4.53621620e-02], [3.46108357e-01, -3.83290703e-02],
235 [3.51347983e-01, -3.44809486e-02], [3.57215426e-01, -3.25163153e-02],
236 [3.62525174e-01, -3.12766064e-02], [3.68462758e-01, -2.97229886e-02],
237 [3.46646908e-01, -2.77590937e-02], [3.20834553e-01, -2.63067663e-02],
238 [2.83582110e-01, -2.36895289e-02], [2.15041020e-01, -1.96734219e-02],
239 [1.36968804e-01, -1.51550643e-02], [2.36080412e-02, -1.40941342e-02],
240 [-1.35145770e-01, -1.09559947e-02], [-2.74106007e-01, -8.94059314e-03],
241 [-3.94680346e-01, -8.25734868e-03], [-4.76913801e-01, -5.34924846e-03],
242 [-4.84515329e-01, -4.41536208e-03], [-5.00000000e-01, -0.00000000e+00],]))
243"""Outline of an *Eigenmannia virescens* viewed from top."""
245Eigenmannia_side = dict(body=np.array([
246 [7.39835590e-02, 4.57421567e-02], [1.36190672e-01, 5.20008556e-02],
247 [1.88575637e-01, 5.31087788e-02], [2.55693889e-01, 4.90162062e-02],
248 [2.91989388e-01, 4.57421567e-02], [3.30997244e-01, 4.08310609e-02],
249 [3.60079352e-01, 3.50312357e-02], [3.86267547e-01, 2.72057399e-02],
250 [4.09748495e-01, 1.88510343e-02], [4.30914243e-01, 1.02069720e-02],
251 [4.43253678e-01, 5.18028074e-03], [4.61959655e-01, -3.75313831e-03],
252 [4.82422519e-01, -1.50677197e-02], [4.93493046e-01, -2.26243878e-02],
253 [4.97325280e-01, -2.75603439e-02], [5.00000000e-01, -3.36538136e-02],
254 [4.99855343e-01, -3.81556262e-02], [4.97829629e-01, -4.26574388e-02],
255 [4.95229403e-01, -4.49683083e-02], [4.93207934e-01, -4.68450344e-02],
256 [4.90607707e-01, -4.83870578e-02], [4.92124870e-01, -5.04085273e-02],
257 [4.93063234e-01, -5.27193968e-02], [4.93063190e-01, -5.47905000e-02],
258 [4.91905677e-01, -5.65722031e-02], [4.87982621e-01, -5.83539496e-02],
259 [4.81889151e-01, -5.99909526e-02], [4.72187579e-01, -6.31614903e-02],
260 [4.57251469e-01, -6.96684443e-02], [4.42315315e-01, -7.44390846e-02],
261 [4.31434877e-01, -7.64563096e-02], [4.21852452e-01, -8.03091592e-02],
262 [4.12030260e-01, -8.11773161e-02], [3.97297016e-01, -8.61380457e-02],
263 [3.84200775e-01, -9.05200184e-02], [3.71589870e-01, -9.38291926e-02],
264 [3.58008292e-01, -9.50424035e-02], [3.33452813e-01, -9.34053571e-02],
265 [2.99075185e-01, -8.68572582e-02], [2.70427177e-01, -8.11276391e-02],
266 [2.32775500e-01, -7.31023958e-02], [2.00034918e-01, -6.81912999e-02],
267 [1.71386866e-01, -6.43481085e-02], [1.37488988e-01, -5.96768656e-02],
268 [8.87168470e-02, -5.53444400e-02], [3.71504052e-02, -5.08426274e-02],
269 [-8.94935470e-03, -4.47741911e-02], [-6.68009664e-02, -3.60218095e-02],
270 [-1.11819296e-01, -3.02864735e-02], [-1.55609841e-01, -2.46444281e-02],
271 [-2.01855938e-01, -1.98208625e-02], [-2.61607520e-01, -1.41655641e-02],
272 [-3.02124011e-01, -9.83500080e-03], [-3.47551590e-01, -8.19795443e-03],
273 [-3.86021794e-01, -7.21576125e-03], [-4.19580907e-01, -5.90618477e-03],
274 [-4.49047446e-01, -5.00584824e-03], [-4.82606558e-01, -4.29793979e-03],
275 [-4.93367213e-01, -3.88865654e-03], [-4.96609514e-01, -3.33497643e-03],
276 [-4.98599358e-01, -2.28352992e-03], [-5.00000000e-01, -4.13646830e-04],
277 [-4.99911798e-01, 1.42799787e-03], [-4.97749085e-01, 3.02268669e-03],
278 [-4.94153971e-01, 3.94706050e-03], [-4.48842818e-01, 5.27946155e-03],
279 [-3.90932887e-01, 5.88974836e-03], [-3.04988822e-01, 7.10408527e-03],
280 [-2.43785835e-01, 8.93052803e-03], [-1.87718481e-01, 1.20250559e-02],
281 [-1.39987578e-01, 1.55534240e-02], [-9.58582596e-02, 1.92113768e-02],
282 [-4.87936436e-02, 2.54739303e-02], [-1.20172913e-02, 3.11685979e-02],
283 [3.65545828e-02, 3.98634200e-02],]),
284 fin0=np.array([
285 [-3.23227396e-01, -8.73526322e-03], [-3.17729007e-01, -1.49720903e-02],
286 [-3.11901320e-01, -2.06301173e-02], [-2.94537996e-01, -2.87329729e-02],
287 [-2.73702014e-01, -3.62471102e-02], [-2.48814582e-01, -4.42901541e-02],
288 [-2.26392044e-01, -4.89203820e-02], [-2.11413629e-01, -4.97652813e-02],
289 [-1.97592770e-01, -4.71608105e-02], [-1.88292360e-01, -4.37113973e-02],
290 [-1.77575020e-01, -4.26201918e-02], [-1.63230314e-01, -4.13425351e-02],
291 [-1.45633053e-01, -4.58128611e-02], [-1.32102997e-01, -5.21132245e-02],
292 [-1.22627830e-01, -5.98022925e-02], [-1.16274541e-01, -6.51393895e-02],
293 [-1.01226326e-01, -6.99292162e-02], [-8.87826127e-02, -7.09420732e-02],
294 [-7.63388990e-02, -7.02186163e-02], [-6.41845810e-02, -6.63566715e-02],
295 [-4.99997329e-02, -6.35107453e-02], [-3.86044383e-02, -6.71556184e-02],
296 [-2.83003535e-02, -7.56835222e-02], [-1.41203129e-02, -8.28817968e-02],
297 [1.21728460e-03, -8.66205668e-02], [1.22140543e-02, -8.75385740e-02],
298 [2.16240177e-02, -8.43285373e-02], [3.27836777e-02, -8.13081568e-02],
299 [3.98554860e-02, -8.02952999e-02], [4.86770343e-02, -7.96350762e-02],
300 [5.81904230e-02, -8.20450399e-02], [6.47198980e-02, -8.65937577e-02],
301 [7.29857310e-02, -9.36024194e-02], [8.47509570e-02, -9.91141438e-02],
302 [1.00477612e-01, -1.02776515e-01], [1.28258936e-01, -1.02826321e-01],
303 [1.45605097e-01, -1.02460349e-01], [1.59342462e-01, -9.97657918e-02],
304 [1.76140399e-01, -9.72111283e-02], [1.89366052e-01, -9.61800377e-02],
305 [2.03938918e-01, -9.84587276e-02], [2.14786136e-01, -1.02170949e-01],
306 [2.24046592e-01, -1.08953357e-01], [2.34464605e-01, -1.14112491e-01],
307 [2.47925953e-01, -1.18114112e-01], [2.65013334e-01, -1.19108779e-01],
308 [2.83520819e-01, -1.15835465e-01], [2.98329467e-01, -1.08650574e-01],
309 [3.15014321e-01, -1.04499489e-01], [3.28805304e-01, -1.04273408e-01],
310 [3.39387031e-01, -1.06211982e-01], [3.52278630e-01, -1.03431974e-01],
311 [3.61896180e-01, -1.00567165e-01], [3.67032403e-01, -9.80662488e-02],
312 [3.71589870e-01, -9.38289761e-02], [3.58008292e-01, -9.50421869e-02],
313 [3.33452813e-01, -9.34051405e-02], [3.06441808e-01, -8.84940880e-02],
314 [2.35043362e-01, -7.35981699e-02], [1.65011316e-01, -6.31802003e-02],
315 [1.25654422e-01, -5.85499724e-02], [9.49792270e-02, -5.56561016e-02],
316 [4.05741354e-02, -5.11056947e-02], [-1.24746680e-03, -4.58268936e-02],
317 [-5.20302500e-02, -3.81131387e-02], [-1.01805114e-01, -3.16101258e-02],
318 [-1.51874267e-01, -2.50855445e-02], [-2.01943420e-01, -2.02074944e-02],
319 [-2.61607516e-01, -1.41653476e-02], [-3.02124016e-01, -9.83478430e-03],
320 [-3.12840355e-01, -9.28491550e-03],]),
321 eye=np.array([0.46, -0.03, 0.005]))
322"""Outline of an *Eigenmannia virescens* viewed from the side."""
324Gpetersii_top = dict(body=np.array([
325 [-5.00000000e-01, 0.00000000e+00], [-4.98907255e-01, 2.70675451e-03],
326 [-4.95224935e-01, 4.98692300e-03], [-4.90164100e-01, 6.33588717e-03],
327 [-4.86097610e-01, 6.53956463e-03], [-4.82786611e-01, 6.60371808e-03],
328 [-4.79368466e-01, 6.66911518e-03], [-4.75847352e-01, 6.73594857e-03],
329 [-4.72227445e-01, 6.80441093e-03], [-4.68512920e-01, 6.87469491e-03],
330 [-4.64707956e-01, 6.94699319e-03], [-4.60816728e-01, 7.02149842e-03],
331 [-4.56843412e-01, 7.09840326e-03], [-4.52792185e-01, 7.17790040e-03],
332 [-4.48667224e-01, 7.26018248e-03], [-4.44472704e-01, 7.34544217e-03],
333 [-4.40212803e-01, 7.43387214e-03], [-4.35891696e-01, 7.52566504e-03],
334 [-4.31513560e-01, 7.62101355e-03], [-4.27082571e-01, 7.72011032e-03],
335 [-4.22602906e-01, 7.82314803e-03], [-4.18078741e-01, 7.93031933e-03],
336 [-4.13514253e-01, 8.04181689e-03], [-4.08913618e-01, 8.15783338e-03],
337 [-4.04281012e-01, 8.27856145e-03], [-3.99620612e-01, 8.40419377e-03],
338 [-3.94936595e-01, 8.53492300e-03], [-3.90233135e-01, 8.67094182e-03],
339 [-3.85514411e-01, 8.81244288e-03], [-3.80784598e-01, 8.95961884e-03],
340 [-3.76047873e-01, 9.11266238e-03], [-3.71308412e-01, 9.27176615e-03],
341 [-3.66570392e-01, 9.43712281e-03], [-3.61837989e-01, 9.60892505e-03],
342 [-3.57115379e-01, 9.78736550e-03], [-3.52406739e-01, 9.97263685e-03],
343 [-3.47716245e-01, 1.01649318e-02], [-3.43048074e-01, 1.03644429e-02],
344 [-3.38406402e-01, 1.05713629e-02], [-3.33795405e-01, 1.07858844e-02],
345 [-3.29219260e-01, 1.10082002e-02], [-3.24682143e-01, 1.12385028e-02],
346 [-3.20188231e-01, 1.14769850e-02], [-3.15741700e-01, 1.17238394e-02],
347 [-3.11346727e-01, 1.19792586e-02], [-3.07007487e-01, 1.22434354e-02],
348 [-3.02469744e-01, 1.25292477e-02], [-2.97839001e-01, 1.28158813e-02],
349 [-2.93275530e-01, 1.30920628e-02], [-2.88774618e-01, 1.33584584e-02],
350 [-2.84331553e-01, 1.36157341e-02], [-2.79941621e-01, 1.38645562e-02],
351 [-2.75600107e-01, 1.41055908e-02], [-2.71302299e-01, 1.43395042e-02],
352 [-2.67043484e-01, 1.45669625e-02], [-2.62818947e-01, 1.47886318e-02],
353 [-2.58623976e-01, 1.50051785e-02], [-2.54453857e-01, 1.52172685e-02],
354 [-2.50303877e-01, 1.54255682e-02], [-2.46169321e-01, 1.56307436e-02],
355 [-2.42045478e-01, 1.58334610e-02], [-2.37927633e-01, 1.60343865e-02],
356 [-2.33811073e-01, 1.62341864e-02], [-2.29691084e-01, 1.64335267e-02],
357 [-2.25562953e-01, 1.66330737e-02], [-2.21421967e-01, 1.68334935e-02],
358 [-2.17263412e-01, 1.70354524e-02], [-2.13082575e-01, 1.72396165e-02],
359 [-2.08874743e-01, 1.74466519e-02], [-2.04635201e-01, 1.76572249e-02],
360 [-2.00359237e-01, 1.78720016e-02], [-1.96042137e-01, 1.80916482e-02],
361 [-1.91679187e-01, 1.83168309e-02], [-1.87265675e-01, 1.85482158e-02],
362 [-1.82796886e-01, 1.87864692e-02], [-1.78268108e-01, 1.90322571e-02],
363 [-1.73674627e-01, 1.92862459e-02], [-1.69011730e-01, 1.95491016e-02],
364 [-1.64274702e-01, 1.98214905e-02], [-1.59458831e-01, 2.01040786e-02],
365 [-1.54876765e-01, 2.03808505e-02], [-1.50542259e-01, 2.06624447e-02],
366 [-1.46207582e-01, 2.09641308e-02], [-1.41872739e-01, 2.12846589e-02],
367 [-1.37537731e-01, 2.16227790e-02], [-1.33202563e-01, 2.19772413e-02],
368 [-1.28867239e-01, 2.23467957e-02], [-1.24531760e-01, 2.27301926e-02],
369 [-1.20196132e-01, 2.31261818e-02], [-1.15860356e-01, 2.35335136e-02],
370 [-1.11524437e-01, 2.39509380e-02], [-1.07188379e-01, 2.43772051e-02],
371 [-1.02852183e-01, 2.48110650e-02], [-9.85158544e-02, 2.52512678e-02],
372 [-9.41793959e-02, 2.56965637e-02], [-8.98428110e-02, 2.61457026e-02],
373 [-8.55061031e-02, 2.65974348e-02], [-8.11692756e-02, 2.70505102e-02],
374 [-7.68323318e-02, 2.75036791e-02], [-7.24952752e-02, 2.79556914e-02],
375 [-6.81581092e-02, 2.84052973e-02], [-6.38208372e-02, 2.88512469e-02],
376 [-5.94834626e-02, 2.92922903e-02], [-5.51459887e-02, 2.97271776e-02],
377 [-5.08084190e-02, 3.01546588e-02], [-4.64707569e-02, 3.05734841e-02],
378 [-4.21330057e-02, 3.09824036e-02], [-3.77951689e-02, 3.13801673e-02],
379 [-3.34572499e-02, 3.17655254e-02], [-2.91192521e-02, 3.21372280e-02],
380 [-2.47811788e-02, 3.24940251e-02], [-2.04430334e-02, 3.28346669e-02],
381 [-1.61048195e-02, 3.31579034e-02], [-1.17665402e-02, 3.34624847e-02],
382 [-7.42819918e-03, 3.37471610e-02], [-3.08979968e-03, 3.40106823e-02],
383 [1.24865487e-03, 3.42517987e-02], [5.58716106e-03, 3.44692604e-02],
384 [9.92571550e-03, 3.46618174e-02], [1.46201447e-02, 3.48571853e-02],
385 [1.92777267e-02, 3.50697277e-02], [2.37992814e-02, 3.52944714e-02],
386 [2.81998991e-02, 3.55299272e-02], [3.24946703e-02, 3.57746059e-02],
387 [3.66986852e-02, 3.60270183e-02], [4.08270342e-02, 3.62856753e-02],
388 [4.48948076e-02, 3.65490876e-02], [4.89170960e-02, 3.68157661e-02],
389 [5.29089894e-02, 3.70842215e-02], [5.68855785e-02, 3.73529647e-02],
390 [6.08619534e-02, 3.76205066e-02], [6.48532046e-02, 3.78853578e-02],
391 [6.88744224e-02, 3.81460293e-02], [7.29406971e-02, 3.84010318e-02],
392 [7.70671192e-02, 3.86488761e-02], [8.12687789e-02, 3.88880731e-02],
393 [8.55607667e-02, 3.91171336e-02], [8.99581728e-02, 3.93345683e-02],
394 [9.44760878e-02, 3.95388881e-02], [9.91296018e-02, 3.97286039e-02],
395 [1.03933805e-01, 3.99022264e-02], [1.08903789e-01, 4.00582663e-02],
396 [1.14054642e-01, 4.01952347e-02], [1.17834449e-01, 4.02735051e-02],
397 [1.21464088e-01, 4.03177574e-02], [1.25361081e-01, 4.03400333e-02],
398 [1.29496398e-01, 4.03422149e-02], [1.33841006e-01, 4.03261843e-02],
399 [1.38365875e-01, 4.02938238e-02], [1.43041974e-01, 4.02470155e-02],
400 [1.47840270e-01, 4.01876413e-02], [1.52731734e-01, 4.01175836e-02],
401 [1.57687333e-01, 4.00387245e-02], [1.62678036e-01, 3.99529460e-02],
402 [1.67674813e-01, 3.98621303e-02], [1.72648631e-01, 3.97681595e-02],
403 [1.77570460e-01, 3.96729159e-02], [1.82411269e-01, 3.95782814e-02],
404 [1.87142025e-01, 3.94861383e-02], [1.91733698e-01, 3.93983686e-02],
405 [1.96157257e-01, 3.93168546e-02], [2.00383670e-01, 3.92434783e-02],
406 [2.04383906e-01, 3.91801218e-02], [2.08128934e-01, 3.91286674e-02],
407 [2.11589723e-01, 3.90909971e-02], [2.14737240e-01, 3.90689931e-02],
408 [2.12686797e-01, 4.35945731e-02], [2.09370932e-01, 4.90028591e-02],
409 [2.06521214e-01, 5.37246134e-02], [2.04069750e-01, 5.78713813e-02],
410 [2.01948645e-01, 6.15547081e-02], [2.00090006e-01, 6.48861392e-02],
411 [1.98425939e-01, 6.79772197e-02], [1.96888549e-01, 7.09394950e-02],
412 [1.95409943e-01, 7.38845104e-02], [1.93922227e-01, 7.69238111e-02],
413 [1.92357507e-01, 8.01689425e-02], [1.90647889e-01, 8.37314498e-02],
414 [1.88621089e-01, 8.79487819e-02], [1.86458315e-01, 9.24949589e-02],
415 [1.84373392e-01, 9.69521163e-02], [1.82377447e-01, 1.01313322e-01],
416 [1.80481608e-01, 1.05571643e-01], [1.78697002e-01, 1.09720148e-01],
417 [1.77034758e-01, 1.13751904e-01], [1.75506002e-01, 1.17659979e-01],
418 [1.74121863e-01, 1.21437441e-01], [1.72893469e-01, 1.25077357e-01],
419 [1.71831946e-01, 1.28572795e-01], [1.70912462e-01, 1.32062919e-01],
420 [1.69673781e-01, 1.37398586e-01], [1.68551414e-01, 1.42827662e-01],
421 [1.67594629e-01, 1.48234120e-01], [1.66852697e-01, 1.53501933e-01],
422 [1.66374886e-01, 1.58515074e-01], [1.66210468e-01, 1.63157516e-01],
423 [1.66408711e-01, 1.67313232e-01], [1.67018885e-01, 1.70866193e-01],
424 [1.68090261e-01, 1.73700374e-01], [1.69672107e-01, 1.75699747e-01],
425 [1.71946252e-01, 1.76778701e-01], [1.75330935e-01, 1.76759167e-01],
426 [1.79335065e-01, 1.75658590e-01], [1.83654362e-01, 1.73730954e-01],
427 [1.87984545e-01, 1.71230243e-01], [1.92021332e-01, 1.68410438e-01],
428 [1.95460443e-01, 1.65525524e-01], [1.98288699e-01, 1.62567524e-01],
429 [2.01008859e-01, 1.59273085e-01], [2.03549954e-01, 1.55804760e-01],
430 [2.05927459e-01, 1.52185189e-01], [2.08156845e-01, 1.48437015e-01],
431 [2.10253586e-01, 1.44582880e-01], [2.12233153e-01, 1.40645424e-01],
432 [2.14111019e-01, 1.36647290e-01], [2.15902657e-01, 1.32611119e-01],
433 [2.17623539e-01, 1.28559552e-01], [2.19289138e-01, 1.24515232e-01],
434 [2.20914927e-01, 1.20500800e-01], [2.22516621e-01, 1.16537119e-01],
435 [2.24093642e-01, 1.12596583e-01], [2.25635202e-01, 1.08661555e-01],
436 [2.27140388e-01, 1.04726305e-01], [2.28608285e-01, 1.00785102e-01],
437 [2.30037979e-01, 9.68322151e-02], [2.31428556e-01, 9.28619142e-02],
438 [2.32779102e-01, 8.88684682e-02], [2.34088702e-01, 8.48461463e-02],
439 [2.35356443e-01, 8.07892177e-02], [2.36581411e-01, 7.66919517e-02],
440 [2.37762692e-01, 7.25486175e-02], [2.38899370e-01, 6.83534843e-02],
441 [2.39990533e-01, 6.41008214e-02], [2.41035267e-01, 5.97848980e-02],
442 [2.42032656e-01, 5.53999834e-02], [2.42981787e-01, 5.09403468e-02],
443 [2.43881746e-01, 4.64002574e-02], [2.44731618e-01, 4.17739844e-02],
444 [2.48004373e-01, 3.96335251e-02], [2.53635676e-01, 4.06269030e-02],
445 [2.58426595e-01, 4.15200350e-02], [2.62587153e-01, 4.23139380e-02],
446 [2.66327377e-01, 4.30096290e-02], [2.69857289e-01, 4.36081248e-02],
447 [2.73386916e-01, 4.41104425e-02], [2.77136095e-01, 4.45185137e-02],
448 [2.81686172e-01, 4.49167415e-02], [2.86059572e-01, 4.52505561e-02],
449 [2.90315087e-01, 4.55181830e-02], [2.94511509e-01, 4.57178472e-02],
450 [2.98707633e-01, 4.58477742e-02], [3.02962251e-01, 4.59061892e-02],
451 [3.07334157e-01, 4.58913175e-02], [3.11882144e-01, 4.58013842e-02],
452 [3.16163999e-01, 4.56260578e-02], [3.20364728e-01, 4.53392745e-02],
453 [3.24552010e-01, 4.49599161e-02], [3.28754468e-01, 4.45083053e-02],
454 [3.33000723e-01, 4.40047646e-02], [3.37319396e-01, 4.34696166e-02],
455 [3.41739110e-01, 4.29231841e-02], [3.46288486e-01, 4.23857894e-02],
456 [3.50619754e-01, 4.29679988e-02], [3.54195757e-01, 4.55158258e-02],
457 [3.58046266e-01, 4.57683865e-02], [3.61404779e-01, 4.41255618e-02],
458 [3.64409935e-01, 4.03824460e-02], [3.68329272e-01, 3.86496012e-02],
459 [3.72644259e-01, 3.78587189e-02], [3.76950817e-01, 3.70760234e-02],
460 [3.81238037e-01, 3.62610245e-02], [3.85495013e-01, 3.53732317e-02],
461 [3.89710839e-01, 3.43721549e-02], [3.93874609e-01, 3.32173035e-02],
462 [3.97975415e-01, 3.18681874e-02], [4.02040813e-01, 3.03843958e-02],
463 [4.06171694e-01, 2.88827227e-02], [4.10325795e-01, 2.73247743e-02],
464 [4.14453652e-01, 2.56705391e-02], [4.18505801e-01, 2.38800060e-02],
465 [4.22432777e-01, 2.19131636e-02], [4.26185115e-01, 1.97300005e-02],
466 [4.29713351e-01, 1.72905055e-02], [4.32968019e-01, 1.45546672e-02],
467 [4.35899655e-01, 1.14824744e-02], [4.37947185e-01, 9.20518422e-03],
468 [4.40409231e-01, 8.23893126e-03], [4.43933454e-01, 7.71247651e-03],
469 [4.48362633e-01, 7.48160487e-03], [4.53539545e-01, 7.40210123e-03],
470 [4.59306972e-01, 7.32975048e-03], [4.65888477e-01, 7.11072685e-03],
471 [4.72579311e-01, 6.83103276e-03], [4.77520884e-01, 6.62053683e-03],
472 [4.81282017e-01, 6.44392261e-03], [4.84431531e-01, 6.26587366e-03],
473 [4.87538245e-01, 6.05107355e-03], [4.91170982e-01, 5.76420583e-03],
474 [4.96599033e-01, 4.75791906e-03], [5.00000000e-01, 2.45820721e-03],
475 [5.00000000e-01, -2.45820721e-03], [4.96599033e-01, -4.75791906e-03],
476 [4.91170982e-01, -5.76420583e-03], [4.87538245e-01, -6.05107355e-03],
477 [4.84431531e-01, -6.26587366e-03], [4.81282017e-01, -6.44392261e-03],
478 [4.77520884e-01, -6.62053683e-03], [4.72579311e-01, -6.83103276e-03],
479 [4.65888477e-01, -7.11072685e-03], [4.59306972e-01, -7.32975048e-03],
480 [4.53539545e-01, -7.40210123e-03], [4.48362633e-01, -7.48160487e-03],
481 [4.43933454e-01, -7.71247651e-03], [4.40409231e-01, -8.23893126e-03],
482 [4.37947185e-01, -9.20518422e-03], [4.35899655e-01, -1.14824744e-02],
483 [4.32968019e-01, -1.45546672e-02], [4.29713351e-01, -1.72905055e-02],
484 [4.26185115e-01, -1.97300005e-02], [4.22432777e-01, -2.19131636e-02],
485 [4.18505801e-01, -2.38800060e-02], [4.14453652e-01, -2.56705391e-02],
486 [4.10325795e-01, -2.73247743e-02], [4.06171694e-01, -2.88827227e-02],
487 [4.02040813e-01, -3.03843958e-02], [3.97975415e-01, -3.18681874e-02],
488 [3.93874609e-01, -3.32173035e-02], [3.89710839e-01, -3.43721549e-02],
489 [3.85495013e-01, -3.53732317e-02], [3.81238037e-01, -3.62610245e-02],
490 [3.76950817e-01, -3.70760234e-02], [3.72644259e-01, -3.78587189e-02],
491 [3.68329272e-01, -3.86496012e-02], [3.64409935e-01, -4.03824460e-02],
492 [3.61404779e-01, -4.41255618e-02], [3.58046266e-01, -4.57683865e-02],
493 [3.54195757e-01, -4.55158258e-02], [3.50619754e-01, -4.29679988e-02],
494 [3.46288486e-01, -4.23857894e-02], [3.41739110e-01, -4.29231841e-02],
495 [3.37319396e-01, -4.34696166e-02], [3.33000723e-01, -4.40047646e-02],
496 [3.28754468e-01, -4.45083053e-02], [3.24552010e-01, -4.49599161e-02],
497 [3.20364728e-01, -4.53392745e-02], [3.16163999e-01, -4.56260578e-02],
498 [3.11882144e-01, -4.58013842e-02], [3.07334157e-01, -4.58913175e-02],
499 [3.02962251e-01, -4.59061892e-02], [2.98707633e-01, -4.58477742e-02],
500 [2.94511509e-01, -4.57178472e-02], [2.90315087e-01, -4.55181830e-02],
501 [2.86059572e-01, -4.52505561e-02], [2.81686172e-01, -4.49167415e-02],
502 [2.77136095e-01, -4.45185137e-02], [2.73386916e-01, -4.41104425e-02],
503 [2.69857289e-01, -4.36081248e-02], [2.66327377e-01, -4.30096290e-02],
504 [2.62587153e-01, -4.23139380e-02], [2.58426595e-01, -4.15200350e-02],
505 [2.53635676e-01, -4.06269030e-02], [2.48004373e-01, -3.96335251e-02],
506 [2.44731618e-01, -4.17739844e-02], [2.43881746e-01, -4.64002574e-02],
507 [2.42981787e-01, -5.09403468e-02], [2.42032656e-01, -5.53999834e-02],
508 [2.41035267e-01, -5.97848980e-02], [2.39990533e-01, -6.41008214e-02],
509 [2.38899370e-01, -6.83534843e-02], [2.37762692e-01, -7.25486175e-02],
510 [2.36581411e-01, -7.66919517e-02], [2.35356443e-01, -8.07892177e-02],
511 [2.34088702e-01, -8.48461463e-02], [2.32779102e-01, -8.88684682e-02],
512 [2.31428556e-01, -9.28619142e-02], [2.30037979e-01, -9.68322151e-02],
513 [2.28608285e-01, -1.00785102e-01], [2.27140388e-01, -1.04726305e-01],
514 [2.25635202e-01, -1.08661555e-01], [2.24093642e-01, -1.12596583e-01],
515 [2.22516621e-01, -1.16537119e-01], [2.20914927e-01, -1.20500800e-01],
516 [2.19289138e-01, -1.24515232e-01], [2.17623539e-01, -1.28559552e-01],
517 [2.15902657e-01, -1.32611119e-01], [2.14111019e-01, -1.36647290e-01],
518 [2.12233153e-01, -1.40645424e-01], [2.10253586e-01, -1.44582880e-01],
519 [2.08156845e-01, -1.48437015e-01], [2.05927459e-01, -1.52185189e-01],
520 [2.03549954e-01, -1.55804760e-01], [2.01008859e-01, -1.59273085e-01],
521 [1.98288699e-01, -1.62567524e-01], [1.95460443e-01, -1.65525524e-01],
522 [1.92021332e-01, -1.68410438e-01], [1.87984545e-01, -1.71230243e-01],
523 [1.83654362e-01, -1.73730954e-01], [1.79335065e-01, -1.75658590e-01],
524 [1.75330935e-01, -1.76759167e-01], [1.71946252e-01, -1.76778701e-01],
525 [1.69672107e-01, -1.75699747e-01], [1.68090261e-01, -1.73700374e-01],
526 [1.67018885e-01, -1.70866193e-01], [1.66408711e-01, -1.67313232e-01],
527 [1.66210468e-01, -1.63157516e-01], [1.66374886e-01, -1.58515074e-01],
528 [1.66852697e-01, -1.53501933e-01], [1.67594629e-01, -1.48234120e-01],
529 [1.68551414e-01, -1.42827662e-01], [1.69673781e-01, -1.37398586e-01],
530 [1.70912462e-01, -1.32062919e-01], [1.71831946e-01, -1.28572795e-01],
531 [1.72893469e-01, -1.25077357e-01], [1.74121863e-01, -1.21437441e-01],
532 [1.75506002e-01, -1.17659979e-01], [1.77034758e-01, -1.13751904e-01],
533 [1.78697002e-01, -1.09720148e-01], [1.80481608e-01, -1.05571643e-01],
534 [1.82377447e-01, -1.01313322e-01], [1.84373392e-01, -9.69521163e-02],
535 [1.86458315e-01, -9.24949589e-02], [1.88621089e-01, -8.79487819e-02],
536 [1.90647889e-01, -8.37314498e-02], [1.92357507e-01, -8.01689425e-02],
537 [1.93922227e-01, -7.69238111e-02], [1.95409943e-01, -7.38845104e-02],
538 [1.96888549e-01, -7.09394950e-02], [1.98425939e-01, -6.79772197e-02],
539 [2.00090006e-01, -6.48861392e-02], [2.01948645e-01, -6.15547081e-02],
540 [2.04069750e-01, -5.78713813e-02], [2.06521214e-01, -5.37246134e-02],
541 [2.09370932e-01, -4.90028591e-02], [2.12686797e-01, -4.35945731e-02],
542 [2.14737240e-01, -3.90689931e-02], [2.11589723e-01, -3.90909971e-02],
543 [2.08128934e-01, -3.91286674e-02], [2.04383906e-01, -3.91801218e-02],
544 [2.00383670e-01, -3.92434783e-02], [1.96157257e-01, -3.93168546e-02],
545 [1.91733698e-01, -3.93983686e-02], [1.87142025e-01, -3.94861383e-02],
546 [1.82411269e-01, -3.95782814e-02], [1.77570460e-01, -3.96729159e-02],
547 [1.72648631e-01, -3.97681595e-02], [1.67674813e-01, -3.98621303e-02],
548 [1.62678036e-01, -3.99529460e-02], [1.57687333e-01, -4.00387245e-02],
549 [1.52731734e-01, -4.01175836e-02], [1.47840270e-01, -4.01876413e-02],
550 [1.43041974e-01, -4.02470155e-02], [1.38365875e-01, -4.02938238e-02],
551 [1.33841006e-01, -4.03261843e-02], [1.29496398e-01, -4.03422149e-02],
552 [1.25361081e-01, -4.03400333e-02], [1.21464088e-01, -4.03177574e-02],
553 [1.17834449e-01, -4.02735051e-02], [1.14054642e-01, -4.01952347e-02],
554 [1.08903789e-01, -4.00582663e-02], [1.03933805e-01, -3.99022264e-02],
555 [9.91296018e-02, -3.97286039e-02], [9.44760878e-02, -3.95388881e-02],
556 [8.99581728e-02, -3.93345683e-02], [8.55607667e-02, -3.91171336e-02],
557 [8.12687789e-02, -3.88880731e-02], [7.70671192e-02, -3.86488761e-02],
558 [7.29406971e-02, -3.84010318e-02], [6.88744224e-02, -3.81460293e-02],
559 [6.48532046e-02, -3.78853578e-02], [6.08619534e-02, -3.76205066e-02],
560 [5.68855785e-02, -3.73529647e-02], [5.29089894e-02, -3.70842215e-02],
561 [4.89170960e-02, -3.68157661e-02], [4.48948076e-02, -3.65490876e-02],
562 [4.08270342e-02, -3.62856753e-02], [3.66986852e-02, -3.60270183e-02],
563 [3.24946703e-02, -3.57746059e-02], [2.81998991e-02, -3.55299272e-02],
564 [2.37992814e-02, -3.52944714e-02], [1.92777267e-02, -3.50697277e-02],
565 [1.46201447e-02, -3.48571853e-02], [9.92571550e-03, -3.46618174e-02],
566 [5.58716106e-03, -3.44692604e-02], [1.24865487e-03, -3.42517987e-02],
567 [-3.08979968e-03, -3.40106823e-02], [-7.42819918e-03, -3.37471610e-02],
568 [-1.17665402e-02, -3.34624847e-02], [-1.61048195e-02, -3.31579034e-02],
569 [-2.04430334e-02, -3.28346669e-02], [-2.47811788e-02, -3.24940251e-02],
570 [-2.91192521e-02, -3.21372280e-02], [-3.34572499e-02, -3.17655254e-02],
571 [-3.77951689e-02, -3.13801673e-02], [-4.21330057e-02, -3.09824036e-02],
572 [-4.64707569e-02, -3.05734841e-02], [-5.08084190e-02, -3.01546588e-02],
573 [-5.51459887e-02, -2.97271776e-02], [-5.94834626e-02, -2.92922903e-02],
574 [-6.38208372e-02, -2.88512469e-02], [-6.81581092e-02, -2.84052973e-02],
575 [-7.24952752e-02, -2.79556914e-02], [-7.68323318e-02, -2.75036791e-02],
576 [-8.11692756e-02, -2.70505102e-02], [-8.55061031e-02, -2.65974348e-02],
577 [-8.98428110e-02, -2.61457026e-02], [-9.41793959e-02, -2.56965637e-02],
578 [-9.85158544e-02, -2.52512678e-02], [-1.02852183e-01, -2.48110650e-02],
579 [-1.07188379e-01, -2.43772051e-02], [-1.11524437e-01, -2.39509380e-02],
580 [-1.15860356e-01, -2.35335136e-02], [-1.20196132e-01, -2.31261818e-02],
581 [-1.24531760e-01, -2.27301926e-02], [-1.28867239e-01, -2.23467957e-02],
582 [-1.33202563e-01, -2.19772413e-02], [-1.37537731e-01, -2.16227790e-02],
583 [-1.41872739e-01, -2.12846589e-02], [-1.46207582e-01, -2.09641308e-02],
584 [-1.50542259e-01, -2.06624447e-02], [-1.54876765e-01, -2.03808505e-02],
585 [-1.59458831e-01, -2.01040786e-02], [-1.64274702e-01, -1.98214905e-02],
586 [-1.69011730e-01, -1.95491016e-02], [-1.73674627e-01, -1.92862459e-02],
587 [-1.78268108e-01, -1.90322571e-02], [-1.82796886e-01, -1.87864692e-02],
588 [-1.87265675e-01, -1.85482158e-02], [-1.91679187e-01, -1.83168309e-02],
589 [-1.96042137e-01, -1.80916482e-02], [-2.00359237e-01, -1.78720016e-02],
590 [-2.04635201e-01, -1.76572249e-02], [-2.08874743e-01, -1.74466519e-02],
591 [-2.13082575e-01, -1.72396165e-02], [-2.17263412e-01, -1.70354524e-02],
592 [-2.21421967e-01, -1.68334935e-02], [-2.25562953e-01, -1.66330737e-02],
593 [-2.29691084e-01, -1.64335267e-02], [-2.33811073e-01, -1.62341864e-02],
594 [-2.37927633e-01, -1.60343865e-02], [-2.42045478e-01, -1.58334610e-02],
595 [-2.46169321e-01, -1.56307436e-02], [-2.50303877e-01, -1.54255682e-02],
596 [-2.54453857e-01, -1.52172685e-02], [-2.58623976e-01, -1.50051785e-02],
597 [-2.62818947e-01, -1.47886318e-02], [-2.67043484e-01, -1.45669625e-02],
598 [-2.71302299e-01, -1.43395042e-02], [-2.75600107e-01, -1.41055908e-02],
599 [-2.79941621e-01, -1.38645562e-02], [-2.84331553e-01, -1.36157341e-02],
600 [-2.88774618e-01, -1.33584584e-02], [-2.93275530e-01, -1.30920628e-02],
601 [-2.97839001e-01, -1.28158813e-02], [-3.02469744e-01, -1.25292477e-02],
602 [-3.07007487e-01, -1.22434354e-02], [-3.11346727e-01, -1.19792586e-02],
603 [-3.15741700e-01, -1.17238394e-02], [-3.20188231e-01, -1.14769850e-02],
604 [-3.24682143e-01, -1.12385028e-02], [-3.29219260e-01, -1.10082002e-02],
605 [-3.33795405e-01, -1.07858844e-02], [-3.38406402e-01, -1.05713629e-02],
606 [-3.43048074e-01, -1.03644429e-02], [-3.47716245e-01, -1.01649318e-02],
607 [-3.52406739e-01, -9.97263685e-03], [-3.57115379e-01, -9.78736550e-03],
608 [-3.61837989e-01, -9.60892505e-03], [-3.66570392e-01, -9.43712281e-03],
609 [-3.71308412e-01, -9.27176615e-03], [-3.76047873e-01, -9.11266238e-03],
610 [-3.80784598e-01, -8.95961884e-03], [-3.85514411e-01, -8.81244288e-03],
611 [-3.90233135e-01, -8.67094182e-03], [-3.94936595e-01, -8.53492300e-03],
612 [-3.99620612e-01, -8.40419377e-03], [-4.04281012e-01, -8.27856145e-03],
613 [-4.08913618e-01, -8.15783338e-03], [-4.13514253e-01, -8.04181689e-03],
614 [-4.18078741e-01, -7.93031933e-03], [-4.22602906e-01, -7.82314803e-03],
615 [-4.27082571e-01, -7.72011032e-03], [-4.31513560e-01, -7.62101355e-03],
616 [-4.35891696e-01, -7.52566504e-03], [-4.40212803e-01, -7.43387214e-03],
617 [-4.44472704e-01, -7.34544217e-03], [-4.48667224e-01, -7.26018248e-03],
618 [-4.52792185e-01, -7.17790040e-03], [-4.56843412e-01, -7.09840326e-03],
619 [-4.60816728e-01, -7.02149842e-03], [-4.64707956e-01, -6.94699319e-03],
620 [-4.68512920e-01, -6.87469491e-03], [-4.72227445e-01, -6.80441093e-03],
621 [-4.75847352e-01, -6.73594857e-03], [-4.79368466e-01, -6.66911518e-03],
622 [-4.82786611e-01, -6.60371808e-03], [-4.86097610e-01, -6.53956463e-03],
623 [-4.90164100e-01, -6.33588717e-03], [-4.95224935e-01, -4.98692300e-03],
624 [-4.98907255e-01, -2.70675451e-03], [-5.00000000e-01, -0.00000000e+00],]))
625"""Outline of an *Gnathonemus petersii* viewed from top."""
627Gpetersii_side = dict(body=np.array([
628 [3.28398160e-01, 5.06559092e-02], [3.19199094e-01, 5.38197145e-02],
629 [3.11056574e-01, 5.67169119e-02], [3.03696263e-01, 5.93946914e-02],
630 [2.96843822e-01, 6.19002432e-02], [2.90224916e-01, 6.42807572e-02],
631 [2.83565204e-01, 6.65834236e-02], [2.76590351e-01, 6.88554323e-02],
632 [2.69026018e-01, 7.11439734e-02], [2.60597868e-01, 7.34962371e-02],
633 [2.51261770e-01, 7.59025132e-02], [2.43304744e-01, 7.78395380e-02],
634 [2.35356403e-01, 7.96898763e-02], [2.27413394e-01, 8.14533275e-02],
635 [2.19472365e-01, 8.31296909e-02], [2.11529962e-01, 8.47187659e-02],
636 [2.03582833e-01, 8.62203518e-02], [1.95627625e-01, 8.76342480e-02],
637 [1.87660985e-01, 8.89602539e-02], [1.79679560e-01, 9.01981688e-02],
638 [1.71679998e-01, 9.13477919e-02], [1.63658946e-01, 9.24089228e-02],
639 [1.55613050e-01, 9.33813608e-02], [1.47538958e-01, 9.42649051e-02],
640 [1.39433318e-01, 9.50593552e-02], [1.31292776e-01, 9.57645104e-02],
641 [1.23120936e-01, 9.63719552e-02], [1.14971217e-01, 9.67676996e-02],
642 [1.06847368e-01, 9.69472966e-02], [9.87430764e-02, 9.69522341e-02],
643 [9.06520304e-02, 9.68239998e-02], [8.25679181e-02, 9.66040816e-02],
644 [7.44844274e-02, 9.63339672e-02], [6.63952465e-02, 9.60551445e-02],
645 [5.82940635e-02, 9.58091011e-02], [5.01745663e-02, 9.56373250e-02],
646 [4.20304431e-02, 9.55813039e-02], [3.38553820e-02, 9.56825256e-02],
647 [2.57298350e-02, 9.58827923e-02], [1.76079099e-02, 9.60920363e-02],
648 [9.48768052e-03, 9.63204279e-02], [1.36979063e-03, 9.65782091e-02],
649 [-6.74511599e-03, 9.68756218e-02], [-1.48563955e-02, 9.72229079e-02],
650 [-2.29634043e-02, 9.76303093e-02], [-3.10654983e-02, 9.81080680e-02],
651 [-3.91620340e-02, 9.86664259e-02], [-4.72523675e-02, 9.93156249e-02],
652 [-5.53358549e-02, 1.00065907e-01], [-6.34118526e-02, 1.00927514e-01],
653 [-7.18993466e-02, 1.02261625e-01], [-8.11969648e-02, 1.04253362e-01],
654 [-8.90809864e-02, 1.05638275e-01], [-9.53015070e-02, 1.04903992e-01],
655 [-1.02836258e-01, 1.02264667e-01], [-1.10086242e-01, 9.86850726e-02],
656 [-1.17131132e-01, 9.44949291e-02], [-1.24050604e-01, 9.00239548e-02],
657 [-1.30924330e-01, 8.56018686e-02], [-1.37851925e-01, 8.14694061e-02],
658 [-1.44838326e-01, 7.73740401e-02], [-1.51858499e-01, 7.32981929e-02],
659 [-1.58924240e-01, 6.92790656e-02], [-1.66047343e-01, 6.53538597e-02],
660 [-1.73239603e-01, 6.15597764e-02], [-1.80512814e-01, 5.79340171e-02],
661 [-1.87878771e-01, 5.45137830e-02], [-1.95349269e-01, 5.13362755e-02],
662 [-2.02936102e-01, 4.84386959e-02], [-2.10670820e-01, 4.57953884e-02],
663 [-2.18446301e-01, 4.33277308e-02], [-2.26244579e-01, 4.10351911e-02],
664 [-2.34068253e-01, 3.89156690e-02], [-2.41919921e-01, 3.69670639e-02],
665 [-2.49802182e-01, 3.51872756e-02], [-2.57717636e-01, 3.35742036e-02],
666 [-2.65668880e-01, 3.21257476e-02], [-2.73658515e-01, 3.08398071e-02],
667 [-2.81689139e-01, 2.97142819e-02], [-2.89763351e-01, 2.87470714e-02],
668 [-2.97883750e-01, 2.79360754e-02], [-3.06009884e-01, 2.72879374e-02],
669 [-3.14146832e-01, 2.68972145e-02], [-3.22397750e-01, 2.67791098e-02],
670 [-3.30694484e-01, 2.69229164e-02], [-3.38968880e-01, 2.73179271e-02],
671 [-3.47152784e-01, 2.79534348e-02], [-3.55178043e-01, 2.88187325e-02],
672 [-3.62976502e-01, 2.99031130e-02], [-3.69491245e-01, 3.10922787e-02],
673 [-3.75027729e-01, 3.30847269e-02], [-3.81405217e-01, 3.62096529e-02],
674 [-3.88406343e-01, 4.02454207e-02], [-3.95813736e-01, 4.49703940e-02],
675 [-4.03410029e-01, 5.01629368e-02], [-4.10977853e-01, 5.56014128e-02],
676 [-4.18299839e-01, 6.10641860e-02], [-4.25158619e-01, 6.63296202e-02],
677 [-4.31760708e-01, 7.17542834e-02], [-4.38394579e-01, 7.77938083e-02],
678 [-4.44929264e-01, 8.41654014e-02], [-4.51237520e-01, 9.05858251e-02],
679 [-4.57192105e-01, 9.67718415e-02], [-4.62665777e-01, 1.02440213e-01],
680 [-4.67531294e-01, 1.07307702e-01], [-4.71931542e-01, 1.11312203e-01],
681 [-4.78923098e-01, 1.15752170e-01], [-4.86766570e-01, 1.17829063e-01],
682 [-4.94275150e-01, 1.15910154e-01], [-5.00000000e-01, 1.10078411e-01],
683 [-4.99192237e-01, 1.02492362e-01], [-4.95460406e-01, 9.53394385e-02],
684 [-4.90446832e-01, 8.86539346e-02], [-4.85474910e-01, 8.23552411e-02],
685 [-4.80116940e-01, 7.63023767e-02], [-4.74386527e-01, 7.03935158e-02],
686 [-4.68507746e-01, 6.45968551e-02], [-4.62704674e-01, 5.88805917e-02],
687 [-4.57087282e-01, 5.31415261e-02], [-4.51221030e-01, 4.74785794e-02],
688 [-4.45249806e-01, 4.20462447e-02], [-4.39272028e-01, 3.66480353e-02],
689 [-4.33386114e-01, 3.10874644e-02], [-4.27293901e-01, 2.49068083e-02],
690 [-4.21087150e-01, 1.80749383e-02], [-4.16972691e-01, 1.18889928e-02],
691 [-4.14100660e-01, 5.57059642e-03], [-4.13927617e-01, -2.87320530e-03],
692 [-4.16518117e-01, -1.03191259e-02], [-4.21249030e-01, -1.68743839e-02],
693 [-4.26080311e-01, -2.35119600e-02], [-4.31143825e-01, -2.98817748e-02],
694 [-4.36565107e-01, -3.57666535e-02], [-4.42259695e-01, -4.15631093e-02],
695 [-4.48046856e-01, -4.73643011e-02], [-4.53759024e-01, -5.32064303e-02],
696 [-4.59228634e-01, -5.91256981e-02], [-4.64931315e-01, -6.50893424e-02],
697 [-4.70589921e-01, -7.07522385e-02], [-4.75576511e-01, -7.69772899e-02],
698 [-4.78536384e-01, -8.45179044e-02], [-4.74937079e-01, -9.12035958e-02],
699 [-4.66829596e-01, -9.29521810e-02], [-4.61234889e-01, -9.14597979e-02],
700 [-4.55669467e-01, -8.90770697e-02], [-4.49258458e-01, -8.57384117e-02],
701 [-4.42087882e-01, -8.14195162e-02], [-4.34243761e-01, -7.60960754e-02],
702 [-4.25812116e-01, -6.97437814e-02], [-4.17545810e-01, -6.28897517e-02],
703 [-4.10849771e-01, -5.68192385e-02], [-4.05159512e-01, -5.14279217e-02],
704 [-3.99837805e-01, -4.65592652e-02], [-3.94247419e-01, -4.20567325e-02],
705 [-3.87639055e-01, -3.76642221e-02], [-3.80497028e-01, -3.35435708e-02],
706 [-3.73372036e-01, -2.99473943e-02], [-3.66154758e-01, -2.67737367e-02],
707 [-3.58735871e-01, -2.39206424e-02], [-3.51006055e-01, -2.12861559e-02],
708 [-3.43031055e-01, -1.88366028e-02], [-3.35174557e-01, -1.68266393e-02],
709 [-3.27215655e-01, -1.52099446e-02], [-3.19183889e-01, -1.39534630e-02],
710 [-3.11108797e-01, -1.30241389e-02], [-3.03019606e-01, -1.23889110e-02],
711 [-2.94902329e-01, -1.21051718e-02], [-2.86785465e-01, -1.22505295e-02],
712 [-2.78689352e-01, -1.28241713e-02], [-2.70634327e-01, -1.38252844e-02],
713 [-2.62640729e-01, -1.52530562e-02], [-2.54843728e-01, -1.70549007e-02],
714 [-2.47426741e-01, -1.90690048e-02], [-2.40252617e-01, -2.12696898e-02],
715 [-2.33188150e-01, -2.36395350e-02], [-2.26100136e-01, -2.61611196e-02],
716 [-2.18855371e-01, -2.88170232e-02], [-2.11320649e-01, -3.15898249e-02],
717 [-2.03362765e-01, -3.44621040e-02], [-1.94848516e-01, -3.74164400e-02],
718 [-1.85644696e-01, -4.04354121e-02], [-1.77857648e-01, -4.29185708e-02],
719 [-1.70156514e-01, -4.54297763e-02], [-1.62430938e-01, -4.80126941e-02],
720 [-1.54702578e-01, -5.06686981e-02], [-1.46993089e-01, -5.33991620e-02],
721 [-1.39324130e-01, -5.62054598e-02], [-1.31717358e-01, -5.90889651e-02],
722 [-1.24194428e-01, -6.20510518e-02], [-1.15662563e-01, -6.55718263e-02],
723 [-1.05305133e-01, -7.02341332e-02], [-9.63092593e-02, -7.46194507e-02],
724 [-8.86323630e-02, -7.85171774e-02], [-8.22318645e-02, -8.17167120e-02],
725 [-7.70651844e-02, -8.40074533e-02], [-7.27307320e-02, -8.52544279e-02],
726 [-6.61297323e-02, -8.61569494e-02], [-5.88746549e-02, -8.65921485e-02],
727 [-5.10837990e-02, -8.66425980e-02], [-4.28754638e-02, -8.63908707e-02],
728 [-3.43679487e-02, -8.59195395e-02], [-2.56795531e-02, -8.53111772e-02],
729 [-1.69285762e-02, -8.46483565e-02], [-8.23331730e-03, -8.40136504e-02],
730 [2.87924220e-04, -8.34896316e-02], [8.52573555e-03, -8.31566770e-02],
731 [1.66602603e-02, -8.29060392e-02], [2.47824955e-02, -8.26453400e-02],
732 [3.28955760e-02, -8.23839938e-02], [4.10026368e-02, -8.21314148e-02],
733 [4.91068127e-02, -8.18970175e-02], [5.72112386e-02, -8.16902162e-02],
734 [6.53190496e-02, -8.15204252e-02], [7.34333805e-02, -8.13970590e-02],
735 [8.15573663e-02, -8.13295317e-02], [8.96941418e-02, -8.13272578e-02],
736 [9.73182938e-02, -8.14294047e-02], [1.05133937e-01, -8.16889268e-02],
737 [1.13212537e-01, -8.20789122e-02], [1.21487501e-01, -8.25701110e-02],
738 [1.29892236e-01, -8.31332728e-02], [1.38360149e-01, -8.37391475e-02],
739 [1.46824648e-01, -8.43584849e-02], [1.55219140e-01, -8.49620349e-02],
740 [1.63477033e-01, -8.55205474e-02], [1.71531735e-01, -8.60047721e-02],
741 [1.79316652e-01, -8.63854590e-02], [1.87152832e-01, -8.66480710e-02],
742 [1.95714938e-01, -8.68587711e-02], [2.03988092e-01, -8.70050279e-02],
743 [2.12037249e-01, -8.70805828e-02], [2.19927361e-01, -8.70791767e-02],
744 [2.27723383e-01, -8.69945509e-02], [2.35490269e-01, -8.68204465e-02],
745 [2.43292970e-01, -8.65506046e-02], [2.51196443e-01, -8.61787663e-02],
746 [2.59265639e-01, -8.56986728e-02], [2.67565512e-01, -8.51040652e-02],
747 [2.76161016e-01, -8.43886846e-02], [2.84315032e-01, -8.35517227e-02],
748 [2.92367976e-01, -8.24952891e-02], [3.00378722e-01, -8.12485380e-02],
749 [3.08356779e-01, -7.98455322e-02], [3.16311653e-01, -7.83203346e-02],
750 [3.24252851e-01, -7.67070080e-02], [3.32189881e-01, -7.50396152e-02],
751 [3.40132248e-01, -7.33522191e-02], [3.48089461e-01, -7.16788824e-02],
752 [3.56071026e-01, -7.00536680e-02], [3.64026861e-01, -6.84887979e-02],
753 [3.72009305e-01, -6.69046200e-02], [3.80051766e-01, -6.54556124e-02],
754 [3.88122672e-01, -6.43368550e-02], [3.96190448e-01, -6.37434279e-02],
755 [4.04340123e-01, -6.37872322e-02], [4.12476471e-01, -6.41239731e-02],
756 [4.20403940e-01, -6.51405095e-02], [4.28117275e-01, -6.73846014e-02],
757 [4.35523022e-01, -7.11297084e-02], [4.42484598e-01, -7.53221252e-02],
758 [4.49115562e-01, -7.98271859e-02], [4.55502974e-01, -8.46869603e-02],
759 [4.61733900e-01, -8.99435183e-02], [4.67658749e-01, -9.54772245e-02],
760 [4.73314668e-01, -1.01437536e-01], [4.78657130e-01, -1.07622152e-01],
761 [4.83476951e-01, -1.14118977e-01], [4.88829477e-01, -1.20095662e-01],
762 [4.96557440e-01, -1.21699267e-01], [5.00000000e-01, -1.15512690e-01],
763 [4.98665409e-01, -1.07139467e-01], [4.95396547e-01, -9.99420672e-02],
764 [4.90643016e-01, -9.32118670e-02], [4.85494221e-01, -8.69406630e-02],
765 [4.80139213e-01, -8.08541451e-02], [4.74769874e-01, -7.47571744e-02],
766 [4.69820081e-01, -6.91463092e-02], [4.64751557e-01, -6.43078085e-02],
767 [4.59059041e-01, -5.97235164e-02], [4.52382076e-01, -5.49860206e-02],
768 [4.44360207e-01, -4.96879085e-02], [4.41478998e-01, -4.45081546e-02],
769 [4.42186082e-01, -3.43341453e-02], [4.41285932e-01, -2.62902902e-02],
770 [4.36671579e-01, -1.97961477e-02], [4.30482679e-01, -1.44337295e-02],
771 [4.24302435e-01, -9.31069238e-03], [4.18173472e-01, -4.20392632e-03],
772 [4.11837700e-01, 9.23360322e-04], [4.05352767e-01, 6.03208266e-03],
773 [3.98776322e-01, 1.10831558e-02], [3.92166014e-01, 1.60374948e-02],
774 [3.85579490e-01, 2.08560149e-02], [3.79074399e-01, 2.54996310e-02],
775 [3.73613887e-01, 2.91974775e-02], [3.67336756e-01, 3.27992505e-02],
776 [3.59583302e-01, 3.68507411e-02], [3.51083120e-01, 4.10070508e-02],
777 [3.42565805e-01, 4.49232811e-02], [3.34760953e-01, 4.82545334e-02]]),
778 fin0=np.array([
779 [-9.23715076e-02, 1.07240277e-01], [-9.35295965e-02, 1.07594433e-01],
780 [-9.67256646e-02, 1.08568249e-01], [-1.01542414e-01, 1.10028743e-01],
781 [-1.07562547e-01, 1.11842936e-01], [-1.14368767e-01, 1.13877847e-01],
782 [-1.21543774e-01, 1.16000494e-01], [-1.28670272e-01, 1.18077899e-01],
783 [-1.35330963e-01, 1.19977081e-01], [-1.41134680e-01, 1.21576288e-01],
784 [-1.46606509e-01, 1.23053436e-01], [-1.52060241e-01, 1.24502551e-01],
785 [-1.57506075e-01, 1.25921270e-01], [-1.62954205e-01, 1.27307227e-01],
786 [-1.68414830e-01, 1.28658058e-01], [-1.73898145e-01, 1.29971399e-01],
787 [-1.79414348e-01, 1.31244885e-01], [-1.84887478e-01, 1.32455496e-01],
788 [-1.90359489e-01, 1.33335047e-01], [-1.96015001e-01, 1.33209743e-01],
789 [-2.01162399e-01, 1.31563565e-01], [-2.04627703e-01, 1.28316201e-01],
790 [-2.07067923e-01, 1.23267049e-01], [-2.08878927e-01, 1.16897283e-01],
791 [-2.10020541e-01, 1.12297166e-01], [-2.11393373e-01, 1.06917040e-01],
792 [-2.12954078e-01, 1.01093164e-01], [-2.14659311e-01, 9.51617962e-02],
793 [-2.16465726e-01, 8.94591952e-02], [-2.18365897e-01, 8.41154074e-02],
794 [-2.20352206e-01, 7.88099956e-02], [-2.22436308e-01, 7.35689663e-02],
795 [-2.24659365e-01, 6.84031347e-02], [-2.27062539e-01, 6.33233164e-02],
796 [-2.29686992e-01, 5.83403267e-02], [-2.32573887e-01, 5.34649810e-02],
797 [-2.36430031e-01, 4.83943841e-02], [-2.41498676e-01, 4.29607364e-02],
798 [-2.46187623e-01, 3.83728372e-02], [-2.48885034e-01, 3.58636954e-02],
799 [-2.48622153e-01, 3.57912618e-02], [-2.46557549e-01, 3.62272274e-02],
800 [-2.43025387e-01, 3.70044307e-02], [-2.38266996e-01, 3.81013749e-02],
801 [-2.32523708e-01, 3.94965634e-02], [-2.26036853e-01, 4.11684994e-02],
802 [-2.19047762e-01, 4.30956865e-02], [-2.11797764e-01, 4.52566278e-02],
803 [-2.04528191e-01, 4.76298267e-02], [-1.97480374e-01, 5.01937866e-02],
804 [-1.91394789e-01, 5.27029072e-02], [-1.86459609e-01, 5.49493825e-02],
805 [-1.81052095e-01, 5.75526666e-02], [-1.75250688e-01, 6.04617194e-02],
806 [-1.69133831e-01, 6.36255006e-02], [-1.62779966e-01, 6.69929702e-02],
807 [-1.56267535e-01, 7.05130879e-02], [-1.49674979e-01, 7.41348134e-02],
808 [-1.43080740e-01, 7.78071067e-02], [-1.36563261e-01, 8.14789275e-02],
809 [-1.30200984e-01, 8.50992356e-02], [-1.24072349e-01, 8.86169909e-02],
810 [-1.18255800e-01, 9.19811531e-02], [-1.12829778e-01, 9.51406820e-02],
811 [-1.07872725e-01, 9.80445375e-02], [-1.03463084e-01, 1.00641679e-01],
812 [-9.96792947e-02, 1.02881067e-01], [-9.65998008e-02, 1.04711661e-01],
813 [-9.43030437e-02, 1.06082421e-01], [-9.28674653e-02, 1.06942306e-01]]),
814 fin1=np.array([
815 [-5.63562109e-02, -8.66230690e-02], [-5.80378311e-02, -8.77598862e-02],
816 [-6.25544177e-02, -9.07828740e-02], [-6.91135601e-02, -9.51108371e-02],
817 [-7.69228473e-02, -1.00162580e-01], [-8.51898685e-02, -1.05356908e-01],
818 [-9.31222129e-02, -1.10112625e-01], [-9.99878561e-02, -1.13889019e-01],
819 [-1.06504731e-01, -1.17311843e-01], [-1.13074811e-01, -1.20683973e-01],
820 [-1.19721672e-01, -1.23894532e-01], [-1.26468889e-01, -1.26832643e-01],
821 [-1.33340040e-01, -1.29387427e-01], [-1.40358701e-01, -1.31448008e-01],
822 [-1.47580880e-01, -1.32990365e-01], [-1.54940053e-01, -1.33335047e-01],
823 [-1.61577933e-01, -1.30712902e-01], [-1.67054395e-01, -1.26102505e-01],
824 [-1.71669835e-01, -1.20355834e-01], [-1.75809346e-01, -1.14080721e-01],
825 [-1.79869801e-01, -1.07847816e-01], [-1.83893833e-01, -1.01567472e-01],
826 [-1.87727742e-01, -9.52536460e-02], [-1.91491183e-01, -8.89575805e-02],
827 [-1.95303810e-01, -8.27305179e-02], [-1.99285279e-01, -7.66237008e-02],
828 [-2.03323939e-01, -7.09497866e-02], [-2.07222716e-01, -6.56608257e-02],
829 [-2.11321456e-01, -6.03101264e-02], [-2.15707243e-01, -5.49148986e-02],
830 [-2.20467161e-01, -4.94923522e-02], [-2.25688295e-01, -4.40596970e-02],
831 [-2.31457727e-01, -3.86341430e-02], [-2.37862543e-01, -3.32328999e-02],
832 [-2.46515829e-01, -2.68980564e-02], [-2.55762572e-01, -2.13588469e-02],
833 [-2.63822695e-01, -1.73872025e-02], [-2.69995895e-01, -1.48443106e-02],
834 [-2.73581870e-01, -1.35913585e-02], [-2.73905506e-01, -1.34429496e-02],
835 [-2.70916623e-01, -1.39170287e-02], [-2.65183910e-01, -1.49680871e-02],
836 [-2.57298969e-01, -1.66581465e-02], [-2.47853402e-01, -1.90492292e-02],
837 [-2.37438812e-01, -2.22033569e-02], [-2.27950178e-01, -2.55768430e-02],
838 [-2.20118830e-01, -2.83655326e-02], [-2.12826783e-01, -3.08912332e-02],
839 [-2.05971274e-01, -3.32032068e-02], [-1.99449541e-01, -3.53507153e-02],
840 [-1.93158823e-01, -3.73830207e-02], [-1.86996359e-01, -3.93493848e-02],
841 [-1.80859385e-01, -4.12990695e-02], [-1.74645142e-01, -4.32813368e-02],
842 [-1.68250866e-01, -4.53454486e-02], [-1.61573797e-01, -4.75406669e-02],
843 [-1.54511172e-01, -4.99162535e-02], [-1.46960230e-01, -5.25214703e-02],
844 [-1.38818209e-01, -5.54055794e-02], [-1.31057252e-01, -5.82788279e-02],
845 [-1.23738218e-01, -6.13446244e-02], [-1.16211608e-01, -6.47801054e-02],
846 [-1.08665309e-01, -6.84191129e-02], [-1.01287211e-01, -7.20954885e-02],
847 [-9.42652035e-02, -7.56430740e-02], [-8.77871747e-02, -7.88957112e-02],
848 [-8.20410142e-02, -8.16872418e-02], [-7.72146108e-02, -8.38515077e-02],
849 [-7.01142594e-02, -8.57539808e-02], [-6.08611143e-02, -8.65416398e-02]]),
850 fin2=np.array([
851 [-4.95709300e-01, 9.71361627e-02], [-4.94727751e-01, 9.40282315e-02],
852 [-4.92102953e-01, 8.63001401e-02], [-4.89531928e-01, 7.93902959e-02],
853 [-4.87029725e-01, 7.32981516e-02], [-4.84335965e-01, 6.75182749e-02],
854 [-4.81551826e-01, 6.25554763e-02], [-4.78127088e-01, 5.76995014e-02],
855 [-4.74138256e-01, 5.27407642e-02], [-4.69901081e-01, 4.78822911e-02],
856 [-4.65707580e-01, 4.32915371e-02], [-4.61429843e-01, 3.88748202e-02],
857 [-4.56778758e-01, 3.47247641e-02], [-4.52133680e-01, 3.06597385e-02],
858 [-4.47773120e-01, 2.62910115e-02], [-4.43994422e-01, 2.12957780e-02],
859 [-4.40936734e-01, 1.58644670e-02], [-4.38682055e-01, 1.00694929e-02],
860 [-4.37395623e-01, 3.93321716e-03], [-4.37251179e-01, -2.22422408e-03],
861 [-4.38411278e-01, -8.31550780e-03], [-4.40881051e-01, -1.40008006e-02],
862 [-4.44310154e-01, -1.91401554e-02], [-4.48235249e-01, -2.40147279e-02],
863 [-4.52186381e-01, -2.88922787e-02], [-4.55951262e-01, -3.38845300e-02],
864 [-4.59685991e-01, -3.88613661e-02], [-4.63182959e-01, -4.39898598e-02],
865 [-4.66221839e-01, -4.94607809e-02], [-4.69128507e-01, -5.63647484e-02],
866 [-4.71915070e-01, -6.41181386e-02], [-4.74263992e-01, -7.12979021e-02],
867 [-4.75857737e-01, -7.64809898e-02], [-4.76376517e-01, -7.82540679e-02],
868 [-4.75295478e-01, -7.70124597e-02], [-4.72622968e-01, -7.39633741e-02],
869 [-4.68700403e-01, -6.95271204e-02], [-4.63869200e-01, -6.41240080e-02],
870 [-4.58470778e-01, -5.81743460e-02], [-4.52846552e-01, -5.20984438e-02],
871 [-4.47337939e-01, -4.63166105e-02], [-4.42286358e-01, -4.12491555e-02],
872 [-4.37409139e-01, -3.64697530e-02], [-4.32541922e-01, -3.13144948e-02],
873 [-4.27898895e-01, -2.59396949e-02], [-4.23628692e-01, -2.04557516e-02],
874 [-4.19879947e-01, -1.49730632e-02], [-4.16801293e-01, -9.60202801e-03],
875 [-4.14541365e-01, -4.45304422e-03], [-4.13248797e-01, 3.63489840e-04],
876 [-4.13063337e-01, 4.59529287e-03], [-4.14062952e-01, 8.03555956e-03],
877 [-4.16210151e-01, 1.20244157e-02], [-4.19333841e-01, 1.64554100e-02],
878 [-4.23262931e-01, 2.12220910e-02], [-4.27826327e-01, 2.62180073e-02],
879 [-4.32852937e-01, 3.13367077e-02], [-4.38171670e-01, 3.64717406e-02],
880 [-4.43611431e-01, 4.15166547e-02], [-4.49001130e-01, 4.63649986e-02],
881 [-4.54169673e-01, 5.09103210e-02], [-4.58945968e-01, 5.50461704e-02],
882 [-4.65985656e-01, 6.14539934e-02], [-4.72468848e-01, 6.79891568e-02],
883 [-4.78279615e-01, 7.43791294e-02], [-4.83358777e-01, 8.04000934e-02],
884 [-4.87647158e-01, 8.58282310e-02], [-4.91085578e-01, 9.04397245e-02],
885 [-4.93614861e-01, 9.40107561e-02], [-4.95175827e-01, 9.63175081e-02]]),
886 eye=np.array([0.36, -0.01, 0.015]))
887"""Outline of an *Gnathonemus petersii* viewed from the side."""
889fish_shapes = dict(Alepto_top=Alepto_top,
890 Alepto_male_side=Alepto_male_side,
891 Eigenmannia_top=Eigenmannia_top,
892 Eigenmannia_side=Eigenmannia_side,
893 Gpetersii_top=Gpetersii_top,
894 Gpetersii_side=Gpetersii_side)
895"""Dictionary holding all electric fish shapes."""
897fish_top_shapes = dict(Alepto=Alepto_top,
898 Eigenmannia=Eigenmannia_top,
899 Gpetersii=Gpetersii_top)
900"""Dictionary holding electric fish shapes viewed from top."""
902fish_side_shapes = dict(Alepto_male=Alepto_male_side,
903 Eigenmannia=Eigenmannia_side,
904 Gpetersii=Gpetersii_side)
905"""Dictionary holding electric fish shapes viewed from the side."""
908def fish_shape(fish):
909 """Get a dictinary containing shapes of a fish.
911 Parameters
912 ----------
913 fish: string or tuple or dict
914 Specifies a fish to show:
915 - any of the strings defining a shape contained in the `fish_shapes` dictionary,
916 - a tuple with the name of the fish as the first element and 'top' or 'side' as the second element,
917 - a dictionary with at least a 'body' key holding pathes to be drawn.
919 Returns
920 -------
921 fish: dict
922 Dictionary with at least a 'body' key holding pathes to be drawn.
923 """
924 if not isinstance(fish, dict):
925 if isinstance(fish, (tuple, list)):
926 if fish[1] == 'top':
927 fish = fish_top_shapes[fish[0]]
928 else:
929 fish = fish_side_shapes[fish[0]]
930 else:
931 fish = fish_shapes[fish]
932 return fish
935def plot_fish(ax, fish, pos=(0, 0), direction=(1, 0), size=20.0, bend=0, scaley=1,
936 bodykwargs={}, finkwargs={}, eyekwargs=None):
937 """Plot body, fins and eye of an electric fish.
939 Parameters
940 ----------
941 ax: matplotlib axes
942 Axes where to draw the fish.
943 fish: string or tuple or dict
944 Specifies a fish to show:
945 - any of the strings defining a shape contained in the `fish_shapes` dictionary,
946 - a tuple with the name of the fish as the first element and 'top' or 'side' as the second element,
947 - a dictionary with at least a 'body' key holding pathes to be drawn.
948 pos: tuple of floats
949 Coordinates of the fish's position (its center).
950 direction: tuple of floats
951 Coordinates of a vector defining the orientation of the fish.
952 size: float
953 Size of the fish.
954 bend: float
955 Bending angle of the fish's tail in degree.
956 scaley: float
957 Scale factor applied in y direction after bending and rotation to
958 compensate for differently scaled axes.
959 bodykwargs: dict
960 Key-word arguments for PathPatch used to draw the fish's body.
961 finkwargs: dict
962 Key-word arguments for PathPatch used to draw the fish's fins.
964 Returns
965 -------
966 bpatch: matplotlib.patches.PathPatch
967 The fish's body. Can be used for set_clip_path().
969 Example
970 -------
972 ```
973 fig, ax = plt.subplots()
974 bodykwargs=dict(lw=1, edgecolor='k', facecolor='k')
975 finkwargs=dict(lw=1, edgecolor='k', facecolor='grey')
976 fish = (('Eigenmannia', 'side'), (0, 0), (1, 0), 20.0, -25)
977 plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs)
978 ax.set_xlim(-15, 15)
979 ax.set_ylim(-10, 10)
980 plt.show()
981 ```
982 """
983 fish = fish_shape(fish)
984 bpatch = None
985 size_fac = 1.1
986 bbox = bbox_pathes(*fish.values())
987 trans = mpl.transforms.Affine2D()
988 angle = np.arctan2(direction[1], direction[0])
989 trans.rotate(angle)
990 #trans.scale(dxu/dyu, dyu/dxu) # what is the right scaling????
991 trans.scale(1, scaley)
992 trans.translate(*pos)
993 for part, verts in fish.items():
994 if part == 'eye':
995 if eyekwargs is not None:
996 verts = np.array(verts)*size*size_fac
997 verts[:2] = trans.transform_point(verts[:2])
998 if not 'zorder' in eyekwargs:
999 eyekwargs['zorder'] = 20
1000 ax.add_patch(Circle(verts[:2], verts[2], **eyekwargs))
1001 continue
1002 verts = bend_path(verts, bend, size, size_fac)
1003 codes = np.zeros(len(verts))
1004 codes[:] = Path.LINETO
1005 codes[0] = Path.MOVETO
1006 codes[-1] = Path.CLOSEPOLY
1007 path = Path(verts, codes)
1008 #pixelx = np.abs(np.diff(ax.get_window_extent().get_points()[:,0]))[0]
1009 #pixely = np.abs(np.diff(ax.get_window_extent().get_points()[:,1]))[0]
1010 #xmin, xmax = ax.get_xlim()
1011 #ymin, ymax = ax.get_ylim()
1012 #dxu = np.abs(xmax - xmin)/pixelx
1013 #dyu = np.abs(ymax - ymin)/pixely
1014 path = path.transformed(trans)
1015 kwargs = bodykwargs if part == 'body' else finkwargs
1016 if not 'zorder' in kwargs:
1017 kwargs['zorder'] = 0 if part == 'body' else 10
1018 patch = PathPatch(path, **kwargs)
1019 if part == 'body':
1020 bpatch = patch
1021 ax.add_patch(patch)
1022 return bpatch
1025def plot_object(ax, pos=(0, 0), radius=1.0, **kwargs):
1026 """Plot circular object.
1028 Parameters
1029 ----------
1030 ax: matplotlib axes
1031 Axes where to draw the object.
1032 pos: tuple of floats
1033 Coordinates of the objects's position (its center).
1034 radius: float
1035 Radius of the cirular object.
1036 kwargs: key word arguments
1037 Arguments for Circle used to draw the obkect.
1038 """
1039 ax.add_patch(Circle(pos, radius, **kwargs))
1042def plot_fishfinder(ax, pos, direction, length, handle=0.05,
1043 central_ground=False, wires=False,
1044 rodkwargs=dict(edgecolor='none', facecolor='gray'),
1045 poskwargs=dict(edgecolor='none', facecolor='red'),
1046 negkwargs=dict(edgecolor='none', facecolor='blue'),
1047 gndkwargs=dict(edgecolor='none', facecolor='black'),
1048 lw=1, zorder=50):
1049 """Plot a fishfinder with electrodes and wires.
1051 Parameters
1052 ----------
1053 ax: matplotlib axes
1054 Axes where to draw the fishfinder.
1055 pos: tuple of floats
1056 Coordinates of the fishfinder's position (its center).
1057 direction: tuple of floats
1058 Coordinates defining the orientation of the fishfinder.
1059 length: float
1060 Length of the fishfinder (center of positive electrode
1061 minus center of negative electrode).
1062 handle: float
1063 Length of handle (rod beyond the negative electrode)
1064 as a fraction of the `length` of fishfinder.
1065 central_ground: bool
1066 Add a central ground electrode.
1067 wires: bool, 'postop' or 'negtop'
1068 Draw wires for each electrode.
1069 - True or 'postop': draw wire of positive electrode on top.
1070 - 'negtop': draw wire of negative electrode on top.
1071 Return the coordinates of the endpoints of the wires.
1072 rodkwargs: dict
1073 Key-word arguments for Rectangle used to draw the rod.
1074 poskwargs: dict
1075 Key-word arguments for Rectangle used to draw the positive electrode.
1076 negkwargs: dict
1077 Key-word arguments for Rectangle used to draw the negative electrode.
1078 gndkwargs: dict
1079 Key-word arguments for Rectangle used to draw the ground electrode.
1080 lw: float
1081 Width of the lines used for drawing the wires.
1082 zorder: int
1083 zorder for the fishfinder.
1085 Returns
1086 -------
1087 negpos: tuple of floats
1088 Coordinates of center of negative electrode.
1089 pospos: tuple of floats
1090 Coordinates of center of positive electrode.
1091 negwirepos: tuple of floats
1092 If `wire`, the end of the wire of the negative electrode.
1093 poswirepos: tuple of floats
1094 If `wire`, the end of the wire of the positive electrode.
1095 gndwirepos: tuple of floats
1096 If `central_ground` and `wire`, the end of the wire of
1097 the ground electrode.
1098 """
1099 width = 0.07*length
1100 transform = mpt.Affine2D().rotate(np.arctan2(direction[1], direction[0])).translate(*pos)
1102 ax.add_patch(Rectangle((-(0.5+handle)*length, -0.5*width),
1103 (1+handle+0.05)*length, width,
1104 transform=transform + ax.transData,
1105 zorder=zorder, **rodkwargs))
1106 ax.add_patch(Rectangle((0.5*length-0.4*width, -0.6*width),
1107 0.8*width, 1.2*width,
1108 transform=transform + ax.transData,
1109 zorder=zorder+2, **poskwargs))
1110 ax.add_patch(Rectangle((-0.5*length-0.4*width, -0.6*width),
1111 0.8*width, 1.2*width,
1112 transform=transform + ax.transData,
1113 zorder=zorder+2, **negkwargs))
1114 nodes = [(-0.5*length, 0), (0.5*length, 0)]
1115 if central_ground:
1116 ax.add_patch(Rectangle((-0.4*width, -0.6*width),
1117 0.8*width, 1.2*width,
1118 transform=transform + ax.transData,
1119 zorder=zorder+2, **gndkwargs))
1120 if wires:
1121 offs = 0.03*width*lw
1122 if wires == 'negtop':
1123 offs *= -1
1124 if central_ground:
1125 offs *= 2
1126 color = negkwargs.get('facecolor')
1127 ax.plot((-0.5*length, -(0.5+handle)*length), (-offs, -offs),
1128 color=color, lw=lw, solid_capstyle='butt',
1129 transform=transform + ax.transData, zorder=zorder+1)
1130 color = poskwargs.get('facecolor')
1131 ax.plot((0.5*length, -(0.5+handle)*length), (offs, offs),
1132 color=color, lw=lw, solid_capstyle='butt', transform=transform +
1133 ax.transData, zorder=zorder+1)
1134 nodes.extend(((-(0.5+handle)*length, -offs), (-(0.5+handle)*length, offs)))
1135 if central_ground:
1136 color = gndkwargs.get('facecolor')
1137 ax.plot((0, -(0.5+handle)*length), (0, 0),
1138 color=color, lw=lw, solid_capstyle='butt',
1139 transform=transform + ax.transData, zorder=zorder+1)
1140 nodes.append((-(0.5+handle)*length, 0))
1141 nodes = transform.transform(nodes)
1142 return nodes
1145def plot_pathes(ax, *vertices, **kwargs):
1146 """Plot pathes.
1148 Parameters
1149 ----------
1150 ax: matplotlib axes
1151 Axes where to draw the path.
1152 vertices: one or more 2D arrays
1153 The coordinates of pathes to be plotted
1154 (first column x-coordinates, second colum y-coordinates).
1155 kwargs: key word arguments
1156 Arguments for PathPatch used to draw the path.
1157 """
1158 for verts in vertices:
1159 codes = np.zeros(len(verts))
1160 codes[:] = Path.LINETO
1161 codes[0] = Path.MOVETO
1162 codes[-1] = Path.CLOSEPOLY
1163 path = Path(verts, codes)
1164 ax.add_patch(PathPatch(path, **kwargs))
1165 bbox = bbox_pathes(*vertices)
1166 center = np.mean(bbox, axis=0)
1167 bbox -= center
1168 bbox *= 1.2
1169 bbox += center
1170 ax.set_xlim(*bbox[:,0])
1171 ax.set_ylim(*bbox[:,1])
1174def fish_surface(fish, pos=(0, 0), direction=(1, 0), size=20.0, bend=0,
1175 gamma=1.0):
1176 """Generate meshgrid of one side of the fish from shape.
1178 Parameters
1179 ----------
1180 fish: string or tuple or dict
1181 Specifies a fish to show:
1182 - any of the strings defining a shape contained in the `fish_shapes` dictionary,
1183 - a tuple with the name of the fish and 'top' or 'side',
1184 - a dictionary with at least a 'body' key holding pathes to be drawn.
1185 pos: tuple of floats
1186 Coordinates of the fish's position (its center).
1187 direction: tuple of floats
1188 Coordinates of a vector defining the orientation of the fish.
1189 size: float
1190 Size of the fish.
1191 bend: float
1192 Bending angle of the fish's tail in degree.
1193 gamma: float
1194 Gamma distortion of the ellipse. The ellipse equation is raised
1195 to the power of gamma before its smaller diameter is scaled up
1196 from one to the actual value.
1198 Returns
1199 -------
1200 xx: 2D array of floats
1201 x-coordinates in direction of body axis.
1202 yy: 2D array of floats
1203 y-coordinates in direction upwards from body axis.
1204 zz: 2D array of floats
1205 z-coordinates of fish surface, outside of fish NaN.
1206 """
1207 if direction[1] != 0:
1208 raise ValueError('rotation not supported by fish_surface yet.')
1209 fish = fish_shape(fish)
1210 bbox = bbox_pathes(*fish.values())
1211 size_fac = -1.05*0.5/bbox[0,0]
1212 path = bend_path(fish['body'], bend, size, size_fac)
1213 # split in top and bottom half:
1214 minxi = np.argmin(path[:,0])
1215 maxxi = np.argmax(path[:,0])
1216 i0 = min(minxi, maxxi)
1217 i1 = max(minxi, maxxi)
1218 path0 = path[i0:i1,:]
1219 path1 = np.vstack((path[i0::-1,:], path[:i1:-1,:]))
1220 if np.mean(path0[:,1]) < np.mean(path1[:,1]):
1221 path0, path1 = path1, path0
1222 # make sure x coordinates are monotonically increasing:
1223 pm = np.maximum.accumulate(path0[:,0])
1224 path0 = np.delete(path0, np.where(path0[:,0] < pm)[0], axis=0)
1225 pm = np.maximum.accumulate(path1[:,0])
1226 path1 = np.delete(path1, np.where(path1[:,0] < pm)[0], axis=0)
1227 # rotate: XXX
1228 # translate:
1229 minx = path[minxi,0] + pos[0]
1230 maxx = path[maxxi,0] + pos[0]
1231 path0 += pos[:2]
1232 path1 += pos[:2]
1233 # interpolate:
1234 n = 5*max(len(path0), len(path1))
1235 #n = 200
1236 x = np.linspace(minx, maxx, n)
1237 upperpath = np.zeros((len(x), 2))
1238 upperpath[:,0] = x
1239 upperpath[:,1] = np.interp(x, path0[:,0], path0[:,1])
1240 lowerpath = np.zeros((len(x), 2))
1241 lowerpath[:,0] = x
1242 lowerpath[:,1] = np.interp(x, path1[:,0], path1[:,1])
1243 # ellipse origin and semi axes:
1244 midline = np.array(upperpath)
1245 midline[:,1] = np.mean(np.vstack((upperpath[:,1], lowerpath[:,1])), axis=0)
1246 diamy = upperpath[:,1] - midline[:,1]
1247 diamz = 0.3*diamy # take it from the top view!
1248 # apply ellipse:
1249 y = np.linspace(np.min(midline[:,1]-diamy), np.max(midline[:,1]+diamy), n//2)
1250 xx, yy = np.meshgrid(x ,y)
1251 zz = diamz * (np.sqrt(1.0 - ((yy-midline[:,1])/diamy)**2))**gamma
1252 return xx, yy, zz
1255def surface_normals(xx, yy, zz):
1256 """Normal vectors on a surface.
1258 Compute surface normals on a surface as returned by `fish_surface()`.
1260 Parameters
1261 ----------
1262 xx: 2D array of floats
1263 Mesh grid of x coordinates.
1264 yy: 2D array of floats
1265 Mesh grid of y coordinates.
1266 zz: 2D array of floats
1267 z-coordinates of surface on the xx and yy coordinates.
1269 Returns
1270 -------
1271 nx: 2D array of floats
1272 x-coordinates of normal vectors for each point in xx and yy.
1273 ny: 2D array of floats
1274 y-coordinates of normal vectors for each point in xx and yy.
1275 nz: 2D array of floats
1276 z-coordinates of normal vectors for each point in xx and yy.
1277 """
1278 dx = xx[0,1] - xx[0,0]
1279 dy = yy[1,0] - yy[0,0]
1280 nx = np.zeros(xx.shape)
1281 nx[:,:-1] = -np.diff(zz, axis=1)/dx
1282 ny = np.zeros(xx.shape)
1283 ny[:-1,:] = -np.diff(zz, axis=0)/dy
1284 nz = np.ones(xx.shape)
1285 norm = np.sqrt(nx*nx+ny*ny+1)
1286 return nx/norm, ny/norm, nz/norm
1289def extract_path(svgfile, path_index, npoints):
1290 """Convert SVG pathes to numpy array with path coordinates.
1292 Draw a fish outline in inkscape and save it to a svg file.
1294 Install the svgpathtools package
1295 (https://github.com/mathandy/svgpathtools):
1296 ```
1297 pip install svgpathtools
1298 ```
1300 Parameters
1301 ----------
1302 svgfile: string
1303 Name of the svg file containing the path.
1304 path_index: int
1305 Index selecting the path.
1306 npoints: int
1307 Number of points to spread out on the path.
1309 Returns
1310 -------
1311 vertices: 2D array
1312 The coordinates of the outline of a fish.
1313 npoints rows of x and y coordinates.
1314 """
1315 from svgpathtools import svg2paths2
1317 paths, attributes, svg_attributes = svg2paths2(svgfile)
1318 path = paths[path_index]
1319 vertices = np.zeros((npoints, 2))
1320 for i in range(npoints):
1321 p = path.point(i/npoints)
1322 vertices[i, 0] = p.real
1323 vertices[i, 1] = p.imag
1324 return vertices
1327def bbox_pathes(*vertices):
1328 """Common bounding box of pathes.
1330 Parameters
1331 ----------
1332 vertices: one or more 2D arrays
1333 The coordinates of pathes
1334 (first column x-coordinates, second colum y-coordinates).
1336 Returns
1337 -------
1338 bbox: 2D array
1339 Bounding box of the pathes: [[x0, y0], [x1, y1]]
1340 """
1341 # get bounding box of all pathes:
1342 bbox = np.zeros((2, 2))
1343 first = True
1344 for verts in vertices:
1345 if len(verts.shape) != 2:
1346 continue
1347 vbbox = np.array([[np.min(verts[:,0]), np.min(verts[:,1])],
1348 [np.max(verts[:,0]), np.max(verts[:,1])]])
1349 if first:
1350 bbox = vbbox
1351 first = False
1352 else:
1353 bbox[0,0] = min(bbox[0,0], vbbox[0,0])
1354 bbox[0,1] = min(bbox[0,1], vbbox[0,1])
1355 bbox[1,0] = max(bbox[1,0], vbbox[1,0])
1356 bbox[1,1] = max(bbox[1,1], vbbox[1,1])
1357 return bbox
1360def translate_pathes(dx, dy, *vertices):
1361 """Translate pathes in place.
1363 Parameters
1364 ----------
1365 dx: float
1366 Shift in x direction.
1367 dy: float
1368 Shift in y direction.
1369 vertices: one or more 2D arrays
1370 The coordinates of pathes to be translated
1371 (first column x-coordinates, second colum y-coordinates).
1372 """
1373 for verts in vertices:
1374 verts[:,0] += dx
1375 verts[:,1] += dy
1378def center_pathes(*vertices):
1379 """Translate pathes to their common origin in place.
1381 Parameters
1382 ----------
1383 vertices: one or more 2D arrays
1384 The coordinates of pathes to be centered
1385 (first column x-coordinates, second colum y-coordinates).
1386 """
1387 center = np.mean(bbox_pathes(*vertices), axis=1)
1388 # shift:
1389 for verts in vertices:
1390 verts[:,0] -= center[0]
1391 verts[:,1] -= center[1]
1394def rotate_pathes(theta, *vertices):
1395 """Rotate pathes in place.
1397 Parameters
1398 ----------
1399 theta: float
1400 Rotation angle in degrees.
1401 vertices: one or more 2D arrays
1402 The coordinates of pathes to be rotated
1403 (first column x-coordinates, second colum y-coordinates).
1404 """
1405 theta *= np.pi/180.0
1406 # rotation matrix:
1407 c = np.cos(theta)
1408 s = np.sin(theta)
1409 rm = np.array(((c, -s), (s, c)))
1410 # rotation:
1411 for verts in vertices:
1412 verts[:,:] = np.dot(verts, rm)
1415def flipx_pathes(*vertices):
1416 """Flip pathes in x-direction in place.
1418 Parameters
1419 ----------
1420 vertices: one or more 2D arrays
1421 The coordinates of pathes to be flipped
1422 (first column x-coordinates, second colum y-coordinates).
1423 """
1424 for verts in vertices:
1425 verts[:,0] = -verts[:,0]
1428def flipy_pathes(*vertices):
1429 """Flip pathes in y-direction in place.
1431 Parameters
1432 ----------
1433 vertices: one or more 2D arrays
1434 The coordinates of pathes to be flipped
1435 (first column x-coordinates, second colum y-coordinates).
1436 """
1437 for verts in vertices:
1438 verts[:,1] = -verts[:,1]
1441def mirror_path(vertices1):
1442 """Complete path of half a fish outline by appending the mirrored path.
1444 It is sufficient to draw half of a top view of a fish. Import with
1445 extract_path() and use this function to add the missing half of the
1446 outline to the path. The outline is mirrored on the x-axis.
1448 Parameters
1449 ----------
1450 vertices1: 2D array
1451 The coordinates of one half of the outline of a fish
1452 (first column x-coordinates, second colum y-coordinates).
1454 Returns
1455 -------
1456 vertices: 2D array
1457 The coordinates of the complete outline of a fish.
1458 """
1459 vertices2 = np.array(vertices1[::-1,:])
1460 vertices2[:,1] *= -1
1461 vertices = np.concatenate((vertices1, vertices2))
1462 return vertices
1465def normalize_path(*vertices):
1466 """Normalize and shift path in place.
1468 The path extent in x direction is normalized to one and its center
1469 is shifted to the origin.
1471 Parameters
1472 ----------
1473 vertices: one or more 2D arrays
1474 The coordinates of the outline of a fish
1475 (first column x-coordinates, second colum y-coordinates).
1476 """
1477 bbox = bbox_pathes(*vertices)
1478 for verts in vertices:
1479 verts[:,1] -= np.mean(bbox[:,1])
1480 verts[:,0] -= bbox[0,0]
1481 verts /= bbox[1,0] - bbox[0,0]
1482 verts[:,0] -= 0.5
1485def bend_path(path, bend, size, size_fac=1.0):
1486 """Bend and scale a path.
1488 Parameters
1489 ----------
1490 path: 2D array
1491 The coordinates of a path.
1492 bend: float
1493 Angle for bending in degrees.
1494 size: float
1495 Scale path to this size.
1496 size_fac: float
1497 Scale path even more, but keep size for calculating the bending.
1499 Returns
1500 -------
1501 path: 2D array
1502 The coordinates of the bent and scaled path.
1503 """
1504 path = np.array(path)
1505 path *= size_fac*size
1506 if np.abs(bend) > 1.e-8:
1507 sel = path[:,0]<0.0
1508 xp = path[sel,0] # all negative x coordinates of path
1509 yp = path[sel,1] # y coordinates of all negative x coordinates of path
1510 r = -180.0*0.5*size/bend/np.pi # radius of circle on which to bend the tail
1511 beta = xp/r # angle on circle for each y coordinate
1512 R = r-yp # radius of point
1513 path[sel,0] = -np.abs(R*np.sin(beta)) # transformed x coordinates
1514 path[sel,1] = r-R*np.cos(beta) # transformed y coordinates
1515 return path
1518def export_path(vertices):
1519 """Print coordinates of path for import as numpy array.
1521 The variable name, a leading 'np.array([' and the closing '])'
1522 are not printed.
1524 Parameters
1525 ----------
1526 vertices: 2D array
1527 The coordinates of the path
1528 (first column x-coordinates, second colum y-coordinates).
1529 """
1530 n = 2
1531 for k, v in enumerate(vertices):
1532 if k%n == 0:
1533 print(' ', end='')
1534 print(' [%.8e, %.8e],' % (v[0], v[1]), end='')
1535 if k%n == n-1 and k < len(vertices)-1:
1536 print('')
1539def export_fish(name, body, *fins):
1540 """Serialize coordinates of fish outlines as a dictionary.
1542 Writes a dictionary with name 'name' and keys 'body', 'fin0', 'fin1', ...
1543 holding the pathes.
1545 Copy these coordinates from the console and paste them into this module.
1546 Give it a proper name and don't forget to add it to the fish_shapes dictionary
1547 to make it know to plot_fish().
1549 Parameters
1550 ----------
1551 name: string
1552 Name of the variable.
1553 body: 2D array
1554 The coordinates of fish's body
1555 (first column x-coordinates, second colum y-coordinates).
1556 fins: zero or more 2D arrays
1557 The coordinates of the fish's fins
1558 (first column x-coordinates, second colum y-coordinates).
1560 Returns
1561 -------
1562 fish: dict
1563 A dictionary holding the pathes that can be passed directly to plot_fish().
1564 """
1565 print('%s = dict(body=np.array([' % name)
1566 export_path(body)
1567 fish = dict(body=body)
1568 for k, f in enumerate(fins):
1569 print(']),')
1570 print(' fin%d=np.array([' % k)
1571 export_path(f)
1572 fish['fin%d' % k] = f
1573 print(']))')
1574 return fish
1577def export_fish_demo():
1578 """Code demonstrating how to export a fish outline from SVG file.
1579 """
1580 body = extract_path('fish.svg', 0, 300)
1581 fin0 = extract_path('fish.svg', 1, 70)
1582 fin1 = extract_path('fish.svg', 2, 70)
1583 verts = (body, fin0, fin1)
1584 # look at the path:
1585 fig, ax = plt.subplots()
1586 plot_pathes(ax, *verts)
1587 ax.set_aspect('equal')
1588 plt.show()
1589 # fix path:
1590 center_pathes(*verts)
1591 rotate_pathes(-90.0, *verts)
1592 #verts[:,1] *= 0.8 # change aspect ratio
1593 #verts = verts[1:,:] # remove first point
1594 #translate_pathes(0.0, -np.min(verts[:,1]), verts)
1595 # mirror, normalize and export path:
1596 #verts = mirror_path(verts)
1597 normalize_path(*verts)
1598 fish = export_fish('fish_side', *verts)
1599 # plot outline:
1600 fig, ax = plt.subplots()
1601 plot_fish(ax, fish, size=1.0/1.1,
1602 bodykwargs=dict(lw=1, edgecolor='k', facecolor='r'),
1603 finkwargs=dict(lw=1, edgecolor='k', facecolor='b'))
1604 ax.set_xlim(-1, 1)
1605 ax.set_ylim(-0.5, 0.5)
1606 plt.show()
1609def main():
1610 """Plot some fish shapes and surface normals.
1611 """
1612 bodykwargs = dict(lw=1, edgecolor='k', facecolor='none')
1613 finkwargs = dict(lw=1, edgecolor='k', facecolor='grey')
1614 eyekwargs = dict(lw=1, edgecolor='white', facecolor='grey')
1615 var = ['zz', 'nx', 'ny', 'nz']
1616 fig, ax = plt.subplots()
1617 for k in range(4):
1618 y = (1.5-k)*9
1619 fish = (('Alepto_male', 'side'), (0, y), (1, 0), 20.0, 0)
1620 xx, yy, zz = fish_surface(*fish, gamma=0.5)
1621 nx, ny, nz = surface_normals(xx, yy, zz)
1622 a = [zz, nx, ny, nz]
1623 th = np.nanmax(np.abs(a[k]))
1624 ax.contourf(xx[0,:], yy[:,0], -a[k], 20, vmin=-th, vmax=th, cmap='RdYlBu')
1625 plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs, eyekwargs=eyekwargs)
1626 ax.text(-11, y+2, var[k])
1627 fish = (('Alepto_male', 'side'), (20, -9), (1, 0), 23.0, 10)
1628 xx, yy, zz = fish_surface(*fish, gamma=0.8)
1629 nv = surface_normals(xx, yy, zz)
1630 ilumn = [-0.05, 0.1, 1.0]
1631 dv = np.zeros(nv[0].shape)
1632 for nc, ic in zip(nv, ilumn):
1633 dv += nc*ic
1634 #ax.contourf(xx[0,:], yy[:,0], dv, 20, cmap='gist_gray')
1635 ax.contourf(xx[0,:], yy[:,0], dv, levels=[np.nanmin(dv), np.nanmin(dv)+0.99*(np.nanmax(dv)-np.nanmin(dv)), np.nanmax(dv)], cmap='gist_gray')
1636 plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs, eyekwargs=eyekwargs)
1637 bodykwargs = dict(lw=1, edgecolor='k', facecolor='k')
1638 fish = (('Alepto', 'top'), (23, 0), (2, 1), 16.0, 25)
1639 plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs)
1640 fish = (('Eigenmannia', 'top'), (23, 8), (1, 0.3), 16.0, -15)
1641 plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs)
1642 fish = (('Eigenmannia', 'side'), (20, 18), (1, 0), 20.0, -25)
1643 plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs, eyekwargs=eyekwargs)
1644 plot_fishfinder(ax, (38, 13), (1, 2), 18, handle=0.2,
1645 central_ground=True, wires=True, lw=2)
1646 plot_fishfinder(ax, (38, -8), (1, 2), 18, central_ground=False)
1647 ax.set_xlim(-15, 45)
1648 ax.set_ylim(-20, 24)
1649 ax.set_aspect('equal')
1650 plt.show()
1653if __name__ == '__main__':
1654 #export_fish_demo()
1655 main()