1

My program makes a simple chart using pygal, and outputs the chart as a URI string. I want to convert this URI into an image that I can then manipulate with pillow. I've tried decoding the string but haven't been able to make it work. The current version of my code takes the URI and converts it into bytes as I was hoping that would make conversion easier, if I don't need to do this I can remove that line.

#Pygal graphing test

import pygal

import base64

from PIL import Image

#Get number of loops needed
user_num = int(input("How many people are taking the survey?"))
print()

#Give values to colour variables
red = 0
orange = 0
yellow = 0
green = 0
blue = 0
purple = 0


#Loop getting data from user
for x in range(1,user_num + 1):

    user_colour = input("What is your favourite colour?")
    print()

    if user_colour == "red":
        red = red + 1

    elif user_colour == "orange":
        orange = orange + 1

    elif user_colour == "yellow":
        yellow = yellow + 1

    elif user_colour == "green":
        green = green + 1

    elif user_colour == "blue":
        blue = blue + 1

    elif user_colour == "purple":
        purple = purple + 1

#Create bar graph object
bar_chart = pygal.Bar()

#Title of graph
bar_chart.title = "Favourite Colour"

#X-Axis label
bar_chart.x_labels = ("Red", "Orange", "Yellow", "Green", "Blue", "Purple")

#Add values
bar_chart.add('Favourite Colours', [red,orange,yellow,green,blue,purple])

#Save chart
data = bar_chart.render_data_uri()

#Convert string to bytes
b = bytes(data, 'utf-8')
Infinity
  • 17
  • 1
  • 3

1 Answers1

0

I was unable to make PIL.Image read the data because the image that you are generating seems to be an SVG image and PIL does not support it. You can check the reasons here.

In order to convert SVG to PNG as described here, we can use cairosvg:

import base64
import io
from PIL import Image
import pygal
from cairosvg import svg2png

# ... your code

# Save chart
data = bar_chart.render_data_uri()

# Remove the header placed by the URI
data = data.replace('data:image/svg+xml;charset=utf-8;base64,', '')

# Convert to bytes
data = data.encode()

# The data is encoded as base64, so we decode it.
data = base64.b64decode(data)

# Open a bytes file object
with io.BytesIO() as f:
    # write the svg data as a png to file object
    svg2png(bytestring=data, write_to=f)

    # read the file object with PIL and display
    img = Image.open(f)
    img.show()

Update

I'd recommend using Anaconda to install cairosvg in an environment. This is what I did to create the environment and install the dependencies.

$ conda create -n test python=3.5
$ source activate test
$ conda install --channel-priority -c conda-forge cairosvg
$ pip install pygal
$ python graph_testing.py  # run code
nitred
  • 5,309
  • 3
  • 25
  • 29
  • I had tried using cairosvg, and while I got it downloaded I couldn't get Cairo to work, so I kept getting an error when trying to import cairosvg – Infinity Jan 06 '18 at 14:40
  • If I'm not wrong `cairo` needs to be built and cannot be installed with just `pip install cairo`. It also needs a bunch of libs to be installed . This is why I prefer Anaconda sometimes because the packages come with all their dependencies including `lib...` files and installs them within the environment and not for the entire system. If you haven't used Anaconda, I recommend giving Anaconda3 a try. – nitred Jan 06 '18 at 15:18
  • Have you considered more easily available options like `matplotlib` or `seaborn` or `pandas` instead of `pygal`? I just went through `pygal` API and it looks like it prefers SVGs which aren't the best format for export into PIL. – nitred Jan 06 '18 at 15:24
  • 1
    I used matplotlib and was able to get my chart working, thanks for the recommendation. – Infinity Jan 06 '18 at 20:52