Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc: provide an usage example of combining fpdf2 with Pygal #652

Closed
Lucas-C opened this issue Dec 29, 2022 · 9 comments · Fixed by #762
Closed

Doc: provide an usage example of combining fpdf2 with Pygal #652

Lucas-C opened this issue Dec 29, 2022 · 9 comments · Fixed by #762

Comments

@Lucas-C
Copy link
Member

Lucas-C commented Dec 29, 2022

We already have a page about Charts & graphs in our documentation, and other ones about combining fpdf2 with other libs.

Pygal seems like a great charting library that can can produces SVG, even if it has received zero development updates for a year now.

It would be interesting to provide a documentation section on how to generate a chart with Pygal and embed it in fpdf2.


By implementing this feature you, as a benevolent FLOSS developper, will provide access to the large community of fpdf2 users to a useful PDF functionality.
As a contributor you will get review feedbacks from maintainers & other contributors, and learn about the lifecycle & structure of a Python library on the way.
You will also be added into the contributors list & map.

This issue can count as part of hacktoberfest

@ssavi-ict
Copy link

Hi @Lucas-C , Would like to contribute in this issue as well.

@Lucas-C
Copy link
Member Author

Lucas-C commented Apr 7, 2023

Hi @Lucas-C , Would like to contribute in this issue as well.

You are very welcome to do so!
Have you started to experiment with Pygal?

This task should be very similar to your great work on PR #746,
but this time the new section should be added to https://github.com/PyFPDF/fpdf2/blob/master/docs/Maths.md

1 similar comment
@Lucas-C
Copy link
Member Author

Lucas-C commented Apr 7, 2023

Hi @Lucas-C , Would like to contribute in this issue as well.

You are very welcome to do so!
Have you started to experiment with Pygal?

This task should be very similar to your great work on PR #746,
but this time the new section should be added to https://github.com/PyFPDF/fpdf2/blob/master/docs/Maths.md

@ssavi-ict
Copy link

ssavi-ict commented Apr 7, 2023

@Lucas-C, Yeah, I started reading some basic snippets using Pygal. I hope I can do this soon.

but this time the new section should be added to https://github.com/PyFPDF/fpdf2/blob/master/docs/Maths.md

How I understood this line is - I need to generate a demo chart using Pygal, embed it in fpdf2, and also provide some documentation. Like, in the section(s) Using Matplotlib, Using Pandas section did.

The new section will be - Using Pygal and it will take place after the Using Plotly section.

Am I correct?

@Lucas-C
Copy link
Member Author

Lucas-C commented Apr 7, 2023

How I understood this line is - I need to generate a demo chart using Pygal, embed it in fpdf2, and also provide some documentation. Like, in the section(s) Using Matplotlib, Using Pandas section did.

You do not need to "embed" it in fpdf2, only to produce some documentation 😊

The new section will be - Using Pygal and it will take place after the Using Plotly section.

Exactly!

@ssavi-ict
Copy link

ssavi-ict commented Apr 9, 2023

Hi @Lucas-C , I have tried almost everything in my mind. It comes down to the following. I found only one way to do that using pygal and fpdf2. It takes more time than I really expect and I do not really like it.

import pygal
from reportlab.graphics import renderPM
from svglib.svglib import svg2rlg
from fpdf import FPDF

# 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 to an SVG and PNG file
bar_chart.render_to_file('bar_chart.svg')
drawing = svg2rlg("bar_chart.svg")
renderPM.drawToFile(drawing, "bar_chart.png")

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

pdf = FPDF()
pdf.add_page()
pdf.image('bar_chart.png', x=x, y=y, w=w, h=h)
pdf.output('bar_chart_pdf.pdf')

I tried with the SVG file generated by the pygal. The fpdf2 generates a black rectangular shape on the PDF. I am not pretty sure if the problem is on the fpdf2 rendering side or in the implementations of pygal side. I tried several other ways. Like reading the SVG image as a byte string (BytesIO) and sending them into the fpdf2.image() method. But it returns the same black rectangle. However, my gut is saying the issue is on the implementation of the pygal side. Because, in the last PR, I used the BytesIO library to get the ByteString of an SVG image using SVGWriter() of Barcode. That did not return any issues then.

Will the above implementation be enough? or do you have any ideas other than this? You can try the following implementation which returns a Black Box-

import pygal
from reportlab.graphics import renderPM
from svglib.svglib import svg2rlg
from fpdf import FPDF

# 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 to an SVG file
bar_chart.render_to_file('bar_chart.svg')

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

pdf = FPDF()
pdf.add_page()
pdf.image('bar_chart.svg', x=x, y=y, w=w, h=h)
pdf.output('bar_chart_pdf.pdf')

I also tried the render_to_png() method from pygal. It requires the CairoSVG library which is a bit problematic in Windows. Also need some DLLs to run the method.

Please let me know any queries.

@Lucas-C
Copy link
Member Author

Lucas-C commented Apr 10, 2023

Thank you for your research @ssavi-ict!

It seems that Pygal introduces <style> & <script> elements to the SVG images it produces:
https://github.com/Kozea/pygal/blob/3.0.0/pygal/svg.py#L449

Sadly, fpdf2 does not currently support those:
https://pyfpdf.github.io/fpdf2/SVG.html#currently-unsupported-notable-svg-features

As a consequence, I fear that we won't be able to embed Pygal graphs as SVG in PDF documents produced by fpdf2 😞

Hence, your approach of embedding charts in a rasterized format seems like the best to me.

However, to convert SVG to a raster image, I don't think that installing reportlabs is needed.
Pygal actually suggests using the cairosvg library: https://github.com/Kozea/pygal/blob/3.0.0/pygal/graph/public.py#L116
We could even suggest to do the conversion in-memory, without writing anything to disk:

img = BytesIO()
cairosvg.svg2png(bar_chart.render(), write_to=img)
pdf.image(img)

Do you feel that you have enough information to start a Pull Request @ssavi-ict? 😊

@ssavi-ict
Copy link

ssavi-ict commented Apr 10, 2023

@Lucas-C , I tried that also.

img = BytesIO()
cairosvg.svg2png(bar_chart.render(), write_to=img)
pdf.image(img)

For this, cairosvg (pip install cairosvg) installations and importing will be required. Along with that if a user uses a windows PC (not sure about another environment) (s)he needs to install GTK (Gnome Toolkit) which can be found Here.

I think we should provide both the solutions with enough explanations (I am OK with that). User can choose based on the requirements. Let me know what you think?
Also, we should mention a little bit of troubleshoot as well.

I will provide the Doc after that. Thank you for the suggestion.

@Lucas-C
Copy link
Member Author

Lucas-C commented Apr 10, 2023

Yes, explaining how to perform the SVG conversion to PNG with both libraries seem like a good idea!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants