savefig and StringIO error on Python3

Dear all,

I’m trying to write a html page content in which a png figure is generated by matplotlib, with Python3.

However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on

TypeError: string argument expected, got ‘bytes’

when on fig.savefig(sio, format=“png”)

Could someone explain me how to do it ?

Best regards,

Julien

···

import matplotlib.pyplot as plt

from io import StringIO

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = StringIO()

fig.savefig(sio, format=“png”)

html = “”"

…a bunch of text and html here…

…more text and html…

""" % sio.getvalue().strip()

Please post the entire traceback so that we can know the context of the error message. Also, exactly which versions of matplotlib and python are you using?

Ben Root

···

On Sat, Nov 1, 2014 at 7:37 AM, Julien Hillairet <julien.hillairet@…287…> wrote:

Dear all,

I’m trying to write a html page content in which a png figure is generated by matplotlib, with Python3.

However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on

TypeError: string argument expected, got ‘bytes’

when on fig.savefig(sio, format=“png”)

Could someone explain me how to do it ?

Best regards,

Julien


import matplotlib.pyplot as plt

from io import StringIO

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = StringIO()

fig.savefig(sio, format=“png”)

html = “”"

…a bunch of text and html here…

…more text and html…

""" % sio.getvalue().strip()


Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users

This works for me with python 3.4.2

import matplotlib.pyplot as plt
from io import BytesIO
import base64

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])

sio = BytesIO()

fig.savefig(sio, format="png")

html = """<html><body>
<img src="data:image/png;base64,{}"/>
</body></html>""".format(base64.encodebytes(sio.getvalue()).decode())

For python 2.7.8 change html =""" to

html = """<html><body>
<img src="data:image/png;base64,%s"/>
</body></html>""" % base64.encodestring(sio.getvalue())

Best regards,
Scott

···

On Nov 1, 2014, at 7:37 AM, Julien Hillairet <julien.hillairet@...287...> wrote:

Dear all,
I'm trying to write a html page content in which a png figure is generated by matplotlib, with Python3.
However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on
TypeError: string argument expected, got 'bytes'
when on fig.savefig(sio, format="png")
Could someone explain me how to do it ?
Best regards,
Julien

--------------------------------------------

import matplotlib.pyplot as plt

from io import StringIO
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])

sio = StringIO()

fig.savefig(sio, format="png")

html = """<html><body>
...a bunch of text and html here...
<img src="data:image/png;base64,%s"/>
...more text and html...
</body></html>""" % sio.getvalue().strip()

------------------------------------------------------------------------------

Many Thanks for your support.

It is Python 3.3.5 and matplotlib 1.4.0

I’ve also found that it worked with ByteIO(), but then I was stuck by the encode/decode things. Thanks very much !

The traceback is below:

Traceback (most recent call last):

File “”, line 1, in
runfile(‘/home/hash/example.py’, wdir=‘/home/hash’)

File “/usr/lib/python3.3/site-packages/spyderlib/widgets/externalshell/sitecustomize.py”, line 586, in runfile
execfile(filename, namespace)

File “/usr/lib/python3.3/site-packages/spyderlib/widgets/externalshell/sitecustomize.py”, line 48, in execfile
exec(compile(open(filename, ‘rb’).read(), filename, ‘exec’), namespace)

File “/home/hash/example.py”, line 10, in
fig.savefig(sio, format=“png”)

File “/usr/lib64/python3.3/site-packages/matplotlib/figure.py”, line 1470, in savefig
self.canvas.print_figure(*args, **kwargs)

File “/usr/lib64/python3.3/site-packages/matplotlib/backend_bases.py”, line 2192, in print_figure
**kwargs)

File “/usr/lib64/python3.3/site-packages/matplotlib/backends/backend_agg.py”, line 525, in print_png
filename_or_obj, self.figure.dpi)

TypeError: string argument expected, got ‘bytes’

···

2014-11-01 17:21 GMT+01:00 Scott Lasley <slasley@…2425…>:

This works for me with python 3.4.2

import matplotlib.pyplot as plt

from io import BytesIO

import base64

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = BytesIO()

fig.savefig(sio, format=“png”)

html = “”"

""".format(base64.encodebytes(sio.getvalue()).decode())

For python 2.7.8 change html =“”" to

html = “”"

""" % base64.encodestring(sio.getvalue())

Best regards,

Scott

On Nov 1, 2014, at 7:37 AM, Julien Hillairet <julien.hillairet@…287…> wrote:

Dear all,

I’m trying to write a html page content in which a png figure is generated by matplotlib, with Python3.

However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on

TypeError: string argument expected, got ‘bytes’

when on fig.savefig(sio, format=“png”)

Could someone explain me how to do it ?

Best regards,

Julien


import matplotlib.pyplot as plt

from io import StringIO

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = StringIO()

fig.savefig(sio, format=“png”)

html = “”"

…a bunch of text and html here…

…more text and html…

""" % sio.getvalue().strip()

Indeed, it works also for me with Python 3.3.5.

Could you explain the changes you made and the reasons behind the byte/string encoding ?

Best regards,

···

2014-11-01 17:21 GMT+01:00 Scott Lasley <slasley@…2425…>:

This works for me with python 3.4.2

import matplotlib.pyplot as plt

from io import BytesIO

import base64

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = BytesIO()

fig.savefig(sio, format=“png”)

html = “”"

""".format(base64.encodebytes(sio.getvalue()).decode())

For python 2.7.8 change html =“”" to

html = “”"

""" % base64.encodestring(sio.getvalue())

Best regards,

Scott

On Nov 1, 2014, at 7:37 AM, Julien Hillairet <julien.hillairet@…287…> wrote:

Dear all,

I’m trying to write a html page content in which a png figure is generated by matplotlib, with Python3.

However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on

TypeError: string argument expected, got ‘bytes’

when on fig.savefig(sio, format=“png”)

Could someone explain me how to do it ?

Best regards,

Julien


import matplotlib.pyplot as plt

from io import StringIO

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = StringIO()

fig.savefig(sio, format=“png”)

html = “”"

…a bunch of text and html here…

…more text and html…

""" % sio.getvalue().strip()

I wish I could say that it was because of a deep understanding of the inner workings of matplotlib or a rock solid grasp of python 3's bytes vs strings, but it wasn't. fig.savefig threw the "TypeError: string argument expected, got 'bytes'" exception, so I figured BytesIO might work better with the binary png data than StringIO, and it did. Your image URI included base64 encoding I added the base64 code and fiddled with decoding to get it to produce ASCII. iPython is great for this sort of playing around with snippets of code.

btw, if you are not aware of the pros and cons of using data uri's to embed images take a look at this Wikipedia page for some helpful information

Apologies if you were expecting a more detailed answer,
Scott

···

On Nov 1, 2014, at 4:37 PM, Julien Hillairet <julien.hillairet@...287...> wrote:

Indeed, it works also for me with Python 3.3.5.

Could you explain the changes you made and the reasons behind the byte/string encoding ?

Best regards,

2014-11-01 17:21 GMT+01:00 Scott Lasley <slasley@...2425...>:
This works for me with python 3.4.2

import matplotlib.pyplot as plt
from io import BytesIO
import base64

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])

sio = BytesIO()

fig.savefig(sio, format="png")

html = """<html><body>
<img src="data:image/png;base64,{}"/>
</body></html>""".format(base64.encodebytes(sio.getvalue()).decode())

For python 2.7.8 change html =""" to

html = """<html><body>
<img src="data:image/png;base64,%s"/>
</body></html>""" % base64.encodestring(sio.getvalue())

Best regards,
Scott

On Nov 1, 2014, at 7:37 AM, Julien Hillairet <julien.hillairet@...287...> wrote:

> Dear all,
> I'm trying to write a html page content in which a png figure is generated by matplotlib, with Python3.
> However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on
> TypeError: string argument expected, got 'bytes'
> when on fig.savefig(sio, format="png")
> Could someone explain me how to do it ?
> Best regards,
> Julien
>
> --------------------------------------------
>
> import matplotlib.pyplot as plt
>
> from io import StringIO
> fig = plt.figure()
> ax = fig.add_subplot(111)
> ax.plot([1,2,3])
>
> sio = StringIO()
>
> fig.savefig(sio, format="png")
>
> html = """<html><body>
> ...a bunch of text and html here...
> <img src="data:image/png;base64,%s"/>
> ...more text and html...
> </body></html>""" % sio.getvalue().strip()
>
> ------------------------------------------------------------------------------

Well, the methodology is sufficient and efficient, I’m OK with that :slight_smile:

Thanks for these additional information.

Regards,

···

Le 2 nov. 2014 09:34, “Scott Lasley” <slasley@…2425…> a écrit :

I wish I could say that it was because of a deep understanding of the inner workings of matplotlib or a rock solid grasp of python 3’s bytes vs strings, but it wasn’t. fig.savefig threw the “TypeError: string argument expected, got ‘bytes’” exception, so I figured BytesIO might work better with the binary png data than StringIO, and it did. Your image URI included base64 encoding I added the base64 code and fiddled with decoding to get it to produce ASCII. iPython is great for this sort of playing around with snippets of code.

btw, if you are not aware of the pros and cons of using data uri’s to embed images take a look at this Wikipedia page for some helpful information

http://en.wikipedia.org/wiki/Data_URI_scheme

Apologies if you were expecting a more detailed answer,

Scott

On Nov 1, 2014, at 4:37 PM, Julien Hillairet <julien.hillairet@…287…> wrote:

Indeed, it works also for me with Python 3.3.5.

Could you explain the changes you made and the reasons behind the byte/string encoding ?

Best regards,

2014-11-01 17:21 GMT+01:00 Scott Lasley <slasley@…2425…>:

This works for me with python 3.4.2

import matplotlib.pyplot as plt

from io import BytesIO

import base64

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = BytesIO()

fig.savefig(sio, format=“png”)

html = “”"

""".format(base64.encodebytes(sio.getvalue()).decode())

For python 2.7.8 change html =“”" to

html = “”"

""" % base64.encodestring(sio.getvalue())

Best regards,

Scott

On Nov 1, 2014, at 7:37 AM, Julien Hillairet <julien.hillairet@…287…> wrote:

Dear all,

I’m trying to write a html page content in which a png figure is generated by matplotlib, with Python3.

However, the following piece of code does not work with matplotlib/Python3 (while it should work with Python2). The error is the following on

TypeError: string argument expected, got ‘bytes’

when on fig.savefig(sio, format=“png”)

Could someone explain me how to do it ?

Best regards,

Julien


import matplotlib.pyplot as plt

from io import StringIO

fig = plt.figure()

ax = fig.add_subplot(111)

ax.plot([1,2,3])

sio = StringIO()

fig.savefig(sio, format=“png”)

html = “”"

…a bunch of text and html here…

…more text and html…

""" % sio.getvalue().strip()

As a side note on the "bytes vs strings" topic, there is PyCon video that I found immensely useful:
Pragmatic Unicode, or How Do I Stop the Pain Pragmatic Unicode | Ned Batchelder
IMHO a 30 minutes talk worth watching.

best,
Pierre

···

Le 02/11/2014 09:34, Scott Lasley a écrit :

I wish I could say that it was because of a deep understanding of the inner workings of matplotlib or a rock solid grasp of python 3's bytes vs strings, but it wasn't. fig.savefig threw the "TypeError: string argument expected, got 'bytes'" exception, so I figured BytesIO might work better with the binary png data than StringIO, and it did.