Repository navigation
Floating point image RGB values must be in the 0..1 range #10372
Copy link
Copy link
Closed
Labels
Description
Bug report
Bug summary
From matplorlib 2.0 to 2.1 this problem appeared: Floating point image RGB values must be in the 0..1 range, instead of producing an image with noise on it.
Code for reproduction
Can use any image to try to reproduce this problem:
import imageio
import numpy as np
from matplotlib.pyplot import imshow
%matplotlib inline
image_file="image.jpg"
content_image = imageio.imread(image_file)
#imshow(content_image)
noise_ratio = 0.6
image_height, image_width, color_channels = content_image.shape
noise_image = np.random.uniform(-20, 20, (1, image_height, image_width, color_channels)).astype('float32')
input_image = noise_image * noise_ratio + content_image * (1 - noise_ratio)
imshow(input_image[0])Actual outcome
<matplotlib.image.AxesImage at 0x7fad8700b748>
Error in callback <function install_repl_displayhook.<locals>.post_execute at 0x7fad44bbb510> (for post_execute):
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~/.local/lib/python3.5/site-packages/matplotlib/pyplot.py in post_execute()
147 def post_execute():
148 if matplotlib.is_interactive():
--> 149 draw_all()
150
151 # IPython >= 2
~/.local/lib/python3.5/site-packages/matplotlib/_pylab_helpers.py in draw_all(cls, force)
134 for f_mgr in cls.get_all_fig_managers():
135 if force or f_mgr.canvas.figure.stale:
--> 136 f_mgr.canvas.draw_idle()
137
138 atexit.register(Gcf.destroy_all)
~/.local/lib/python3.5/site-packages/matplotlib/backend_bases.py in draw_idle(self, *args, **kwargs)
2053 if not self._is_idle_drawing:
2054 with self._idle_draw_cntx():
-> 2055 self.draw(*args, **kwargs)
2056
2057 def draw_cursor(self, event):
~/.local/lib/python3.5/site-packages/matplotlib/backends/backend_agg.py in draw(self)
429 # if toolbar:
430 # toolbar.set_cursor(cursors.WAIT)
--> 431 self.figure.draw(self.renderer)
432 finally:
433 # if toolbar:
~/.local/lib/python3.5/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
53 renderer.start_filter()
54
---> 55 return draw(artist, renderer, *args, **kwargs)
56 finally:
57 if artist.get_agg_filter() is not None:
~/.local/lib/python3.5/site-packages/matplotlib/figure.py in draw(self, renderer)
1473
1474 mimage._draw_list_compositing_images(
-> 1475 renderer, self, artists, self.suppressComposite)
1476
1477 renderer.close_group('figure')
~/.local/lib/python3.5/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
136 if not_composite or not has_images:
137 for a in artists:
--> 138 a.draw(renderer)
139 else:
140 # Composite any adjacent images together
~/.local/lib/python3.5/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
53 renderer.start_filter()
54
---> 55 return draw(artist, renderer, *args, **kwargs)
56 finally:
57 if artist.get_agg_filter() is not None:
~/.local/lib/python3.5/site-packages/matplotlib/axes/_base.py in draw(self, renderer, inframe)
2579 renderer.stop_rasterizing()
2580
-> 2581 mimage._draw_list_compositing_images(renderer, self, artists)
2582
2583 renderer.close_group('axes')
~/.local/lib/python3.5/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
136 if not_composite or not has_images:
137 for a in artists:
--> 138 a.draw(renderer)
139 else:
140 # Composite any adjacent images together
~/.local/lib/python3.5/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
53 renderer.start_filter()
54
---> 55 return draw(artist, renderer, *args, **kwargs)
56 finally:
57 if artist.get_agg_filter() is not None:
~/.local/lib/python3.5/site-packages/matplotlib/image.py in draw(self, renderer, *args, **kwargs)
566 else:
567 im, l, b, trans = self.make_image(
--> 568 renderer, renderer.get_image_magnification())
569 if im is not None:
570 renderer.draw_image(gc, l, b, im)
~/.local/lib/python3.5/site-packages/matplotlib/image.py in make_image(self, renderer, magnification, unsampled)
793 return self._make_image(
794 self._A, bbox, transformed_bbox, self.axes.bbox, magnification,
--> 795 unsampled=unsampled)
796
797 def _check_unsampled_image(self, renderer):
~/.local/lib/python3.5/site-packages/matplotlib/image.py in _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification, unsampled, round_to_pixel_border)
484 # (of int or float)
485 # or an RGBA array of re-sampled input
--> 486 output = self.to_rgba(output, bytes=True, norm=False)
487 # output is now a correctly sized RGBA array of uint8
488
~/.local/lib/python3.5/site-packages/matplotlib/cm.py in to_rgba(self, x, alpha, bytes, norm)
254 if xx.dtype.kind == 'f':
255 if norm and xx.max() > 1 or xx.min() < 0:
--> 256 raise ValueError("Floating point image RGB values "
257 "must be in the 0..1 range.")
258 if bytes:
ValueError: Floating point image RGB values must be in the 0..1 range.
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/usr/local/lib/python3.5/dist-packages/IPython/core/formatters.py in __call__(self, obj)
339 pass
340 else:
--> 341 return printer(obj)
342 # Finally look for special method names
343 method = get_real_method(obj, self.print_method)
/usr/local/lib/python3.5/dist-packages/IPython/core/pylabtools.py in <lambda>(fig)
236
237 if 'png' in formats:
--> 238 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
239 if 'retina' in formats or 'png2x' in formats:
240 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
/usr/local/lib/python3.5/dist-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
120
121 bytes_io = BytesIO()
--> 122 fig.canvas.print_figure(bytes_io, **kw)
123 data = bytes_io.getvalue()
124 if fmt == 'svg':
~/.local/lib/python3.5/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, **kwargs)
2210 orientation=orientation,
2211 dryrun=True,
-> 2212 **kwargs)
2213 renderer = self.figure._cachedRenderer
2214 bbox_inches = self.figure.get_tightbbox(renderer)
~/.local/lib/python3.5/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, *args, **kwargs)
506
507 def print_png(self, filename_or_obj, *args, **kwargs):
--> 508 FigureCanvasAgg.draw(self)
509 renderer = self.get_renderer()
510 original_dpi = renderer.dpi
~/.local/lib/python3.5/site-packages/matplotlib/backends/backend_agg.py in draw(self)
429 # if toolbar:
430 # toolbar.set_cursor(cursors.WAIT)
--> 431 self.figure.draw(self.renderer)
432 finally:
433 # if toolbar:
~/.local/lib/python3.5/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
53 renderer.start_filter()
54
---> 55 return draw(artist, renderer, *args, **kwargs)
56 finally:
57 if artist.get_agg_filter() is not None:
~/.local/lib/python3.5/site-packages/matplotlib/figure.py in draw(self, renderer)
1473
1474 mimage._draw_list_compositing_images(
-> 1475 renderer, self, artists, self.suppressComposite)
1476
1477 renderer.close_group('figure')
~/.local/lib/python3.5/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
136 if not_composite or not has_images:
137 for a in artists:
--> 138 a.draw(renderer)
139 else:
140 # Composite any adjacent images together
~/.local/lib/python3.5/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
53 renderer.start_filter()
54
---> 55 return draw(artist, renderer, *args, **kwargs)
56 finally:
57 if artist.get_agg_filter() is not None:
~/.local/lib/python3.5/site-packages/matplotlib/axes/_base.py in draw(self, renderer, inframe)
2579 renderer.stop_rasterizing()
2580
-> 2581 mimage._draw_list_compositing_images(renderer, self, artists)
2582
2583 renderer.close_group('axes')
~/.local/lib/python3.5/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
136 if not_composite or not has_images:
137 for a in artists:
--> 138 a.draw(renderer)
139 else:
140 # Composite any adjacent images together
~/.local/lib/python3.5/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
53 renderer.start_filter()
54
---> 55 return draw(artist, renderer, *args, **kwargs)
56 finally:
57 if artist.get_agg_filter() is not None:
~/.local/lib/python3.5/site-packages/matplotlib/image.py in draw(self, renderer, *args, **kwargs)
566 else:
567 im, l, b, trans = self.make_image(
--> 568 renderer, renderer.get_image_magnification())
569 if im is not None:
570 renderer.draw_image(gc, l, b, im)
~/.local/lib/python3.5/site-packages/matplotlib/image.py in make_image(self, renderer, magnification, unsampled)
793 return self._make_image(
794 self._A, bbox, transformed_bbox, self.axes.bbox, magnification,
--> 795 unsampled=unsampled)
796
797 def _check_unsampled_image(self, renderer):
~/.local/lib/python3.5/site-packages/matplotlib/image.py in _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification, unsampled, round_to_pixel_border)
484 # (of int or float)
485 # or an RGBA array of re-sampled input
--> 486 output = self.to_rgba(output, bytes=True, norm=False)
487 # output is now a correctly sized RGBA array of uint8
488
~/.local/lib/python3.5/site-packages/matplotlib/cm.py in to_rgba(self, x, alpha, bytes, norm)
254 if xx.dtype.kind == 'f':
255 if norm and xx.max() > 1 or xx.min() < 0:
--> 256 raise ValueError("Floating point image RGB values "
257 "must be in the 0..1 range.")
258 if bytes:
ValueError: Floating point image RGB values must be in the 0..1 range.
<Figure size 432x288 with 1 Axes>
Expected outcome
In matplotlib==2.0.2 and previous this code generates a image with some noise applied to it.
In matplotlib=2.1.x the error above appear.
Matplotlib version
- Operating system: ubuntu 16.04
- Matplotlib version: 2.1.X
- Matplotlib backend (print(matplotlib.get_backend())): module://ipykernel.pylab.backend_inline
- Python version: 3.5.2
- Jupyter version (if applicable): Jupyterlab==0.30.6
- Other libraries:
numpy==1.14.0
imageio==2.2.0
The libraries are installed in pure python via pip install. I also build from the source to test if a recent unreleased version had this problem solved this but also got the same output.
Reactions are currently unavailable
Activity
jklymak commentedon Feb 2, 2018
I think #10220 addresses this by clipping, but its not merged yet
ImportanceOfBeingErnest commentedon Feb 3, 2018
This error needs to be seen as a feature. It tells the user that what he is supplying to imshow is not a valid RGB image, because it has values outside of the range [0.,1.] in it.
Since there are essentially a multitude of possible "desired outcomes" when supplying such an array (e.g. should the array be normalized, should each channel be normalized, should it be clipped?) it should be the user's responsibility to create a valid RGB(A) image from the array.
I guess the documentation is already quite clear, saying
although one might change "should" to "must" if people feel like it is not precise enough.
cyberwillis commentedon Feb 3, 2018
[UPDATED]
I appreciate your answer but In any case in the earlier version of matplotlib the same documentation point this out and worked nice. But changing the version from matplotlib==2.0.2 to 2.1.x stopped to work. To me is clear that is a bug.
In case I pass a uniform distribution (from NEGATIVE to POSITIVE) it not works but if I pass a distribution (from ZERO to INFINITY) it should ? where the constrain about 0 to 1 is happening here ?
jklymak commentedon Feb 3, 2018
The converse could also be considered true if you are of the camp that the user must supply valid inputs: it was a bug before 2.1.x that got fixed. Anyway, this is duplicate of #10220 so feel free to comment on the proposed new behaviour there. Or if I'm mistaken and this is actually not a duplicate, please feel free to ask that it is re-opened.
ImportanceOfBeingErnest commentedon Feb 3, 2018
Sorry, my point is that the fact that it used to work was a bug, which is now repaired by throwing the correct error if invalid RGBA image is passed onto
imshow. From some yet-to-be released version on, there will be a warning, instead of an error in such cases, as seen in the duplicate.cyberwillis commentedon Feb 3, 2018
Thank you all for your explanations. Looking forward to see the fix in the future release.
ImportanceOfBeingErnest commentedon Feb 3, 2018
@cyberwillis You are correct, the case where the input array range is strictly positive and exceeds 1, e.g. [0.,200000000.] should not be supported either. With the linked fix, it will throw a warning as well.
In any case, you need to make sure that your array is in the range between [0.,1.] to be correctly shown as image. With the fix in place you will equally be forced to do that, so there is actually no reason to be looking forward to it.