Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scaling issue Matplotlib

I am in the process of using matplotlib in Python to create a template that can be used for cutting material to sew a garment (a pattern).

I am actually really happy with how the plot has come out. All the functionality I needed could be found in matplotlib.

The main (and quite major) issue is with scale. When I save this out as a pdf, each square measures to be about 0.75 cm when it should be 1cm. This is reflected also in the plot e.g. the distance between p0 and p1 should be 41.5cm and the actual length in the exported document is 31.8cm.

I have attached a quick screenshot of a section of the plot.

Below is how I am saving the plot as a pdf.

Any advice would be greatly appreciated.

# Marking lines
fig, ax = plt.subplots()

# Setting plot limits and equal aspect ratio
ax.set_xlim(-1, 20)
ax.set_ylim(-2, 85)
ax.set_aspect('equal')

# Add grid lines for 1 cm squares
# To convert from data units to cm units, you need to know the figure size and dpi
fig_width_cm = fig.get_size_inches()[0] * 2.54  # convert from inches to cm
fig_height_cm = fig.get_size_inches()[1] * 2.54

# Assuming a dpi of 300
dpi = 300
x_ticks = np.arange(-1, 20, 1)  
y_ticks = np.arange(-2, 85, 1)  
ax.set_xticks(x_ticks)
ax.set_yticks(y_ticks)

# Showing grid and inverting y-axis
ax.grid(True)
plt.gca().invert_yaxis()

# Define DPI (dots per inch)
dpi = 300


# Convert axis limits to inches
x_range_in_inches = (21 / 2.54)  # Conversion from cm to inches
y_range_in_inches = (87 / 2.54)  # Conversion from cm to inches

# Set the figure size based on the axis limits
fig.set_size_inches(x_range_in_inches, y_range_in_inches, forward=True)

# Save the figure with only the visible area
file_path = 'E:/#DOCUMENTS/#Code/high_resolution_plot.pdf'
fig.savefig(file_path, dpi=dpi, bbox_inches='tight', pad_inches=0.1, transparent=True) 

# Display the plot
plt.show()

plt.close(fig)

I understand that it has to do with matplotlib using inches as its standard unit of measurement - and maybe something to do with DPI when it is exported.

like image 935
Sven Avatar asked Sep 02 '26 05:09

Sven


2 Answers

I adapted your code so that it works as expected. You will need to update it like the margins but above all the dpi. To compute your dpi, find your screen resolution, let's say it's 1600 x 900. Then measure the width of your screen e.g. 45cm i.e. 17.7 inches, your dpi is 1600 / 17.7 = 90.4.
I checked that the dimensions were correct on my screen and on the saved image (with zoom=100%) but I could not check on a printer.

# dots per inch
dpi = 106

# cm to inch
left_margin, right_margin = 1 / 2.54, 1 / 2.54
ax_width, ax_height = 21 / 2.54, 87  / 2.54
top_margin, bottom_margin = 1 / 2.54, 1 / 2.54

fig_width = left_margin + ax_width + right_margin   
fig_height = top_margin + ax_height + bottom_margin 

fig, ax = plt.subplots(figsize=(fig_width, fig_height), dpi=dpi)    

fig.subplots_adjust(left = left_margin / fig_width,
                    bottom = bottom_margin / fig_height,
                    right = 1 - right_margin / fig_width,
                    top = 1 - top_margin   / fig_height )
                                   
# Setting plot limits and equal aspect ratio
ax.set_xlim(-1, 20)
ax.set_ylim(-2, 85)
ax.set_aspect('equal')

x_ticks = np.arange(-1, 20, 1)  
y_ticks = np.arange(-2, 85, 1)  
ax.set_xticks(x_ticks)
ax.set_yticks(y_ticks)

# Showing grid and inverting y-axis
ax.grid(True)
plt.gca().invert_yaxis()

# Save the figure with only the visible area
file_path = 'testjpg.jpg'
fig.savefig(file_path, dpi=dpi, transparent=True)

# Display the plot
plt.show()
like image 115
rehaqds Avatar answered Sep 03 '26 17:09

rehaqds


I tested with a simple 10cm line and it worked using Ruth C's suggestion :) https://matplotlib.org/stable/gallery/axes_grid1/demo_fixed_size_axes.html

from mpl_toolkits.axes_grid1 import Divider, Size
import matplotlib.pyplot as plt

# Define the DPI and conversion factor from cm to inches
dpi = 300
cm_to_inch = 1 / 2.54  # Conversion factor from cm to inches

# Define the figure size in inches
fig = plt.figure(figsize=(10 * cm_to_inch, 5 * cm_to_inch), dpi=dpi)  # 10cm wide, 5cm high figure

# Define the sizes of the axes
h = [Size.Fixed(1), Size.Fixed(10), Size.Fixed(1)]  # Horizontal: 10 cm fixed size
v = [Size.Fixed(1), Size.Fixed(1), Size.Fixed(1)]  # Vertical: Padding around

# Create a divider to manage axes positions
divider = Divider(fig, (0, 0, 1, 1), h, v, aspect=False)

# Add an axes object with a fixed position
ax = fig.add_axes(divider.get_position(), axes_locator=divider.new_locator(nx=1, ny=1))

# Draw a horizontal line from 0 to 10 cm
ax.plot([0, 10], [0, 0], 'k-', linewidth=2)  # Black line, 2 px width

# Set limits to ensure the line fits perfectly within the axes
ax.set_xlim(0, 10)
ax.set_ylim(-1, 1)

# Remove ticks and labels for clarity
ax.set_xticks([])
ax.set_yticks([])
ax.axis('off')

# Save the figure
file_path = "E:/#DOCUMENTS/#Code/horizontal_line_10cm.pdf"
fig.savefig(file_path, dpi=dpi, bbox_inches="tight", transparent=True)

# Display the plot
plt.show()
plt.close(fig)
like image 36
Sven Avatar answered Sep 03 '26 17:09

Sven



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!