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