Jesper Larsen
2015-04-24 12:38:08 UTC
Hi Matplotlib Users,
When I make wind barbs with rounding enabled and custom barb increments I
noticed that there were no wind barbs with half barbs above 2 full barbs.
The reason seems to be a bug in the _find_tails method. The bug is
illustrated by this small script (_find_tails is a copy of the one in
matplotlib):
import numpy as np
def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50):
'''
Find how many of each of the tail pieces is necessary. Flag
specifies the increment for a flag, barb for a full barb, and half for
half a barb. Mag should be the magnitude of a vector (ie. >= 0).
This returns a tuple of:
(*number of flags*, *number of barbs*, *half_flag*, *empty_flag*)
*half_flag* is a boolean whether half of a barb is needed,
since there should only ever be one half on a given
barb. *empty_flag* flag is an array of flags to easily tell if
a barb is empty (too low to plot any barbs/flags.
'''
#If rounding, round to the nearest multiple of half, the smallest
#increment
if rounding:
mag = half * (mag / half + 0.5).astype(np.int)
num_flags = np.floor(mag / flag).astype(np.int)
mag = np.mod(mag, flag)
num_barb = np.floor(mag / full).astype(np.int)
mag = np.mod(mag, full)
half_flag = mag >= half
empty_flag = ~(half_flag | (num_flags > 0) | (num_barb > 0))
return num_flags, num_barb, half_flag, empty_flag
def main():
mag = np.arange(0,21,1)
barb_incs = {'half': 2.57222,
'full': 5.14444,
'flag': 25.7222}
print 'With rounding'
num_flags, num_barb, half_flag, empty_flag = _find_tails(None, mag,
rounding=True, **barb_incs)
for i in range(len(mag)):
print mag[i], num_flags[i], num_barb[i], half_flag[i], empty_flag[i]
print 'Without rounding'
num_flags, num_barb, half_flag, empty_flag = _find_tails(None, mag,
rounding=False, **barb_incs)
for i in range(len(mag)):
print mag[i], num_flags[i], num_barb[i], half_flag[i], empty_flag[i]
if __name__ == '__main__':
exit(main())
It seems like the error is not present when the barb increments are not
set. I believe the reason for the bug is the float comparison (half_flag =
mag >= half) where the value is rounded to a value very close to/identical
to the 'half' increment. And it seems like python does the right thing when
the "half" increment is a whole number but not always when it is not.
But in any case the code should probably not depend two floats being equal.
Best regards,
Jesper
When I make wind barbs with rounding enabled and custom barb increments I
noticed that there were no wind barbs with half barbs above 2 full barbs.
The reason seems to be a bug in the _find_tails method. The bug is
illustrated by this small script (_find_tails is a copy of the one in
matplotlib):
import numpy as np
def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50):
'''
Find how many of each of the tail pieces is necessary. Flag
specifies the increment for a flag, barb for a full barb, and half for
half a barb. Mag should be the magnitude of a vector (ie. >= 0).
This returns a tuple of:
(*number of flags*, *number of barbs*, *half_flag*, *empty_flag*)
*half_flag* is a boolean whether half of a barb is needed,
since there should only ever be one half on a given
barb. *empty_flag* flag is an array of flags to easily tell if
a barb is empty (too low to plot any barbs/flags.
'''
#If rounding, round to the nearest multiple of half, the smallest
#increment
if rounding:
mag = half * (mag / half + 0.5).astype(np.int)
num_flags = np.floor(mag / flag).astype(np.int)
mag = np.mod(mag, flag)
num_barb = np.floor(mag / full).astype(np.int)
mag = np.mod(mag, full)
half_flag = mag >= half
empty_flag = ~(half_flag | (num_flags > 0) | (num_barb > 0))
return num_flags, num_barb, half_flag, empty_flag
def main():
mag = np.arange(0,21,1)
barb_incs = {'half': 2.57222,
'full': 5.14444,
'flag': 25.7222}
print 'With rounding'
num_flags, num_barb, half_flag, empty_flag = _find_tails(None, mag,
rounding=True, **barb_incs)
for i in range(len(mag)):
print mag[i], num_flags[i], num_barb[i], half_flag[i], empty_flag[i]
print 'Without rounding'
num_flags, num_barb, half_flag, empty_flag = _find_tails(None, mag,
rounding=False, **barb_incs)
for i in range(len(mag)):
print mag[i], num_flags[i], num_barb[i], half_flag[i], empty_flag[i]
if __name__ == '__main__':
exit(main())
It seems like the error is not present when the barb increments are not
set. I believe the reason for the bug is the float comparison (half_flag =
mag >= half) where the value is rounded to a value very close to/identical
to the 'half' increment. And it seems like python does the right thing when
the "half" increment is a whole number but not always when it is not.
But in any case the code should probably not depend two floats being equal.
Best regards,
Jesper