Skip to content

Commit

Permalink
DOC: Chart Using PyGal added (#762)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssavi-ict committed Apr 12, 2023
1 parent f3dadb3 commit 393580e
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ This can also be enabled programmatically with `warnings.simplefilter('default',

## [2.7.4] - Not released yet

### Added
- documentation on how to embed `graphs` and `charts` generated using `Pygal` lib: [documentation section](https://pyfpdf.github.io/fpdf2/Maths.html#using-pygal) - thanks to @ssavi-ict

## [2.7.3] - 2023-04-03
### Fixed
- removed a debug `print()` statement left in `output.py:OutputProducer._add_fonts()` 🤦‍♂️ - A rule was also added to `.pre-commit-config.yaml` to avoid this to happen again.
Expand Down
101 changes: 101 additions & 0 deletions docs/Maths.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,107 @@ Result:
![](plotly_svg.png)


## Using Pygal ##
[Pygal](https://www.pygal.org/en/stable/) is a graph plotting library using Python. You can install Pygal using `pip install pygal` command.

`fpdf2` is able to embed the graph and charts that are generated using `Pygal` library. The following ways explain how to embed `Pygal` charts into `fpdf2` library. However, we can not embed graphs as SVG directly. Since, `Pygal` introduces `<style>` & `<script>` elements to the `SVG` images it produces ([Ref](https://github.com/Kozea/pygal/blob/3.0.0/pygal/svg.py#L449)) which is currently not supported by `fpdf2`. The full list of unsupported SVG features of `fpdf2` is [there](https://pyfpdf.github.io/fpdf2/SVG.html#currently-unsupported-notable-svg-features).

### Using cairosvg (*A faster and efficient implementation*) ###

A faster and expected approach of embedding a `Pygal` svg graph into a PDF file is to use the `cairosvg` library to convert the `svg` string generated by `pygal` into byte string using `BytesIO` library so that we can keep these data in an in-memory buffer.
As the `fpdf` library can understand byte string of a `svg` content, it can easily embed a graph inside a `pdf`.

```python
import pygal
from fpdf import FPDF
from io import BytesIO
import cairosvg

# Create a Pygal bar chart
bar_chart = pygal.Bar()
bar_chart.title = 'Browser usage evolution (in %)'
bar_chart.x_labels = map(str, range(2002, 2013))
bar_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1])
bar_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3])
bar_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])
bar_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5])

# Use CairoSVG to convert PNG from SVG of barchart
svg_img_bytesio = BytesIO()
cairosvg.svg2png(bar_chart.render(), write_to=svg_img_byte)

# Set the position and size of the image in the PDF
x = 50
y = 50
w = 100
h = 70

# Make the PDF
pdf = FPDF()
pdf.add_page()
pdf.image(svg_img_byte, x=x, y=y, w=w, h=h)
pdf.output('bar_chart.pdf')
```
The above code generates a pdf with title `bar_chart.pdf` file with following graph -
![](pygal_chart_cairo.PNG)

**!! Troubleshoot: !!**

You may encounter `GTK` (Gnome Toolkit) errors while executing the above example in windows. Error could be like following -
```
OSError: no library called "cairo-2" was found
no library called "cairo" was found
no library called "libcairo-2" was found
cannot load library 'libcairo.so.2': error 0x7e
cannot load library 'libcairo.2.dylib': error 0x7e
cannot load library 'libcairo-2.dll': error 0x7e
```
In this case install install `GTK` from [GTK-for-Windows-Runtime-Environment-Installer](https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases). Restart your editor. And you are all done.

### Using svglib and reportlab (*A slower and purely pythonic implementation*) ###
```python
import io
import pygal
from reportlab.graphics import renderPM
from svglib.svglib import SvgRenderer
from fpdf import FPDF
from lxml import etree

# Create a Pygal bar chart
bar_chart = pygal.Bar()
bar_chart.title = 'Sales by Year'
bar_chart.x_labels = ['2016', '2017', '2018', '2019', '2020']
bar_chart.add('Product A', [500, 750, 1000, 1250, 1500])
bar_chart.add('Product B', [750, 1000, 1250, 1500, 1750])

# Render the chart and convert it to a bytestring object
svg_img = bar_chart.render()
svg_root = etree.fromstring(svg_img)
drawing = SvgRenderer(svg_img).render(svg_root)
drawing_img_byte = renderPM.drawToString(drawing)
img_bytes = io.BytesIO(drawing_img_byte)

# Set the position and size of the image in the PDF
x = 50
y = 50
w = 100
h = 70

# Make the PDF
pdf = FPDF()
pdf.add_page()
pdf.image(img_bytes, x=x, y=y, w=w, h=h)
pdf.output('bar_chart_pdf.pdf')
```
User who are using `reportlab` and `svglib` to work with `svg` images and are intended to render `svg` images `reportlab` and `svglib` can use this library. However, it consumes a little bit more time than the previous example.

The above code shows following output -
![](pygal_chart.png)

**Why there is a performance issue between `cairosvg` and `svglib`?**

*Regarding performance, cairosvg is generally faster than svglib when it comes to rendering SVG files to other formats. This is because cairosvg is built on top of a fast C-based rendering engine, while svglib is written entirely in Python. Additionally, cairosvg offers various options for optimizing the rendering performance, such as disabling certain features, like fonts or filters.*

## Mathematical formulas ##
`fpdf2` can only insert mathematical formula in the form of **images**.
The following sections will explaing how to generate and embed such images.
Expand Down
Binary file added docs/pygal_chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/pygal_chart_cairo.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 393580e

Please sign in to comment.