I’m creating a program, which places circles on a fixed graph based on user input, and after that the user has the option to generate a PDF from that figure. However, if I try to save the figure as PDF, the figure never keeps it’s exact physical size, but it is very important. For example, if my math is right, the Y axis should be always 100mm long, as you can see in the adjust_graph_X() function. The user has the option to relength the X axis, thats why we have this adjust function. After generating the PDF, the Y axis is never 100mm on the PDF, it is bigger, or smaller, depending on the X axis length, and the PDF autoscale or I do not know.
import matplotlib.pyplot as plt from matplotlib.backends.backend_pdf import PdfPages import tkinter as tk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure
fig, ax = plt.subplots(figsize=(210/25.4, 297/25.4), dpi=96) # Define PDF size in mm (A4) 210x297mm fig.suptitle(f"Enter name", fontsize=14)
#Create canvas to display the figure canvas = FigureCanvasTkAgg(fig, master=window) canvas.get_tk_widget().pack(side="right", expand=False, fill="none")
`def adjust_graph_x():
global pixels_per_1mm
global graph_diameter
global x_axis_length_pixels
global y_axis_length_pixels
pixels_per_1mm = window.winfo_fpixels('1m') # Return the number of pixels for 1mm distance
graph_diameter = float(entry_graft_diameter.get()) #user input based, must adjust the x axis length
x_axis_length_mm = graph_diameter * math.pi #d*pi circle area
x_axis_length_pixels = pixels_per_1mm * x_axis_length_mm
#x_axis_length_pixels = (x_axis_length_mm * 96) / 25.4 #96 dpi
dpi = pixels_per_1mm * 25.4
print(dpi)
global pixel_distance_x
pixel_distance_x = x_axis_length_pixels / 720 #720 values between 6h AM and 6h PM, evenly divided
y_axis_length_mm = 100
y_axis_length_pixels = pixels_per_1mm * y_axis_length_mm
ax.clear()
# Set X-axis limits and aspect ratio
ax.set_xlim(0, x_axis_length_pixels)
ax.set_ylim(y_axis_length_pixels, 0)
# Create custom X-axis ticks and labels at specific hour intervals
hours = ['6h', '7h', '8h', '9h', '10h', '11h', '12h', '1h', '2h', '3h', '4h', '5h', '6h']
tick_positions = [i * (pixel_distance_x * 60) for i in range(len(hours))]
ax.set_xticks(tick_positions) # Set tick positions
ax.set_xticklabels(hours) # Set labels
# Create custom Y-axis ticks and labels at specific intervals (10mm)
distances = ['0mm', '10mm', '20mm', '30mm', '40mm', '50mm', '60mm', '70mm', '80mm', '90mm', '100mm']
y_ticks = [i * (pixels_per_1mm*10) for i in range(11)] # placing distance labels with 10mm step
ax.set_yticks(y_ticks) # Set y-axis tick positions
ax.set_yticklabels(distances) # Set labels
ax.grid(True, which='both', linestyle='--', linewidth=0.5)
# Draw a thicker vertical line at 12h
twelve_hour_position = tick_positions[6] # Assuming '12h' is at index 6
ax.axvline(twelve_hour_position, color='black', linewidth=2, linestyle='--')
ax.axis('on')
canvas.draw()
draw_circles_and_show_preview(circle_data)`
For example, the graft_diameter_entry()
is 25mm, with that we get X axis length 78,54mm , and let’s say the user draws 1 circle like this:
After that we generate the PDF, and as you can see with Adobe PDF measuring tool, the Y axis is nearly 120mm instead of fixed 100:
I have tried a lot of PDF generation methods, including:
`pp = PdfPages(filename)
pp.savefig(fig, dpi=96)
pp.close()`
or
`canvas.print_figure(filename, dpi=96)`
or
`width=fig.get_figwidth()
height=fig.get_figheight()
fig.set_size_inches(width, height)
fig.set_dpi(96)
fig.savefig(filename, dpi=96)`
I also tried saving the figure to image, then reload it and adjust it accordingly:
`canvas2 = Canvas(filename, pagesize=A4)
canvas2.drawImage("my_figure.png",0,0,width=x_axis_length_pixels, height=y_axis_length_pixels, preserveAspectRatio=True)
canvas2.showPage()
canvas2.save()`
My new, and last Idea is that i’ll create a new canvas with
`from reportlab.pdfgen.canvas import Canvas`
and with that I will redraw the whole thing with lines and circles like this:
`canvas2.circle(1 * mm, 9 * mm, 0.5 * mm, stroke=1, fill=0) etc....`
because i’m getting done with the simple PDF saver functions. What am I doing wrong? All of the generation methods optimize my figure someway, so I cannot get the figure size which I draw on the monitor.