Make a PNG-image column with python

I would like to generate some custom python plots for every row of an input table.

I managed to use the Python View node for that but it is limited for the output to one PNG image at a time.
I was wondering if there is a way to use a classical Python Script node to directly put some PNG plots into a “plot” column, like other types of variable. That would save some execution time.

2 Likes

Hi l.thomas,

The simplest way to do this that currently comes to mind would be by using the
KNIME Image Processing community contribution which also features an extension for Python. This allows you to wrap numpy.ndarrays in individual KNIPImage objects on Python side which you can put into the output pandas.DataFrame of nodes like the Python Script (1⇒1) node like any other kind of data. They are then translated to ImgPlus data cells on KNIME side which you can convert into PNGs using the ImgPlus to PNG Images node. An example Python script can be found on the page of the Python extension to which I linked above.

Marcel

1 Like

Thanks for the answer, I know this method of putting a numpy array into a KNIPImage object, but I was hoping that there could be a possibility to also output directly a PNG, similar to the python view node.

Indeed, the python view node is shipped with a template code that shows how to save the plot as PNG or SVG from matplotlib to a buffer variable. I can possibly get a numpy array from the matplotlib plot but it is less pythonic in a way :stuck_out_tongue:

For what it’s worth, looking at our Python integration’s source code suggests that KNIME is also capable of directly converting images of Python type PIL.PngImagePlugin.PngImageFile into KNIME image cells. Maybe that’s an alternative (but honestly, I have no idea how to create a PngImageFile and I’ve never seen someone using that functionality so far).

1 Like

Given this hint, I guess it should be possible to do something along these lines:

1 Like

I found a way with SVG not with PNG but that’s fine :slight_smile:

That’s actually what is used for the python view node as well, using matplotlib instead of PILimage to save the buffer.
And it turns out that the resulting string of buffer.getvalue() can be stored in a string column, then rendered to an image by pluging a string to SVG node after the python node :slight_smile:

plt.savefig(buffer, format='svg')
output_table['plot']=[buffer.getvalue()]

The only thing is that the SVG cannot be viewed in the ImageViewer but by increasing the row height and column width the image is scaling accordingly so I’m fine with it.

Trying the same thing with PNG returns the error
Execute failed: 'utf8' codec can't decode byte 0x89 in position 0: invalid start byte

Just to make sure I understand correctly: is this what you tried?

plt.savefig(buffer, format='png')

Yes indeed, I did not try saving as a PNG with PILimage, only Matplotlib, but that could possibly work.

Hm, this rather suggests that the string buffer is not UTF8-encoded.

See also:

By the way, I just realized that the XML string for the SVG figure differs between Python 2/Matplotlib 2.2.3 and Python3/Matplotlib 3.0.3.
In Python3, the string was encoded as byte so the command has to be modified with .decode("utf-8")

plt.savefig(buffer, format='svg')
output_table['plot']=[buffer.getvalue().decode("utf-8")]

I expect something similar for PNG with a different argument for decode but I could not find out.

2 Likes

Hi,

did anyone ever have success with PNG columns?
I cannot get it to work, and SVG is too slow for thousands of data points.
With PNG, python produces a byte vector column and if I then use e.g. a “Renderer to Image columns” node, all the images are just white.

I actually got it to work today, with the snippet from another forum post.
Pretty hacky but it works.

Would be nice if there would be a bit better image support for scripting (e.g. being able to set an image type column directly).

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.