0

I am using Python 3 and Flask with Matplotlib and numpy.

I wish to load pages that generate many plots which are embedded into the page.

I have tried following suggestions made in other places, such as this stackoverflow question and this github post.

However, when I try to implement anything of the kind I get all kinds of IO related errors. Usually of the form:

TypeError: string argument expected, got 'bytes'

and is generated inside of:

site-packages/matplotlib/backends/backend_agg.py

specifically the print_png function

I understand python3 no longer has a StringIO import, which is what is producing the error, and instead we are to import io and call it with io.StringIO() - at least that is what I understand we are to do, however, I can't seem to get any of the examples I have found to work.

The structure of my example is almost identical to that of the stackoverflow question listed above. The page generates as does the image route. It is only the image generation itself that fails.

I am happy to try a different strategy if someone has a better idea. To be clear, I need to generate plots - some times many (100+ on any single page and hundreds of pages) - from data in a database and display them on a webpage. I was hoping to avoid generating files that I then have to clean up given the large number of files I will probably generate and the fact they may change as data in the DB changes.

Community
  • 1
  • 1
tanbog
  • 600
  • 9
  • 28
  • 1
    This error means that you have to `decode()` from bytes to string using 'utf-8' or other encodings. Problem is because in Python2 there was no difference between `str` and `bytes`. And Python3 use `unicode` as `str`. – furas Oct 10 '16 at 02:35
  • Yes, but where, the error is inside the matplotlib package. My access to it is in the `savefig(img)` call and I can't decode that to a string. I assume the problem lies in the line `img = io.StringIO()` that precedes it but I do not know how else to create an object to save the figure and pass back to the rendering engine. – tanbog Oct 10 '16 at 03:49
  • It is the `img = io.StringIO()` line it should be `img = io.BytesIO()` – tanbog Oct 10 '16 at 04:05

1 Answers1

2

The code taken from this stackoverflow question which is used in the above question contains the following:

    import StringIO
    ...
    fig = draw_polygons(cropzonekey)
    img = StringIO()
    fig.savefig(img)

As poitned out by @furas, Python3 treats bytes and strings differently to Python2. In many Python 2 examples StringIO is used for cases like the above but in Python3 it will not work. Therefore, we need modify the above like this:

    import io
    ...
    fig = draw_polygons(cropzonekey)
    img = BytesIO()
    fig.savefig(img)

Which appears to work.

Community
  • 1
  • 1
tanbog
  • 600
  • 9
  • 28