Skip to content

Commit 4c04ad5

Browse files
authored
fix: restore PDF coordinate scaling (fixes #985)
- Independent X/Y scaling in PDF coordinate mapping - Update coord context before mapping line/text - Aligns data with axes/ticks; CI green Closes #985.
1 parent bfc3921 commit 4c04ad5

File tree

2 files changed

+25
-61
lines changed

2 files changed

+25
-61
lines changed

src/backends/vector/fortplot_pdf.f90

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ subroutine draw_pdf_line(this, x1, y1, x2, y2)
9898
class(pdf_context), intent(inout) :: this
9999
real(wp), intent(in) :: x1, y1, x2, y2
100100
real(wp) :: pdf_x1, pdf_y1, pdf_x2, pdf_y2
101-
101+
! Ensure coordinate context reflects latest figure ranges and plot area
102+
call this%update_coord_context()
103+
102104
call normalize_to_pdf_coords(this%coord_ctx, x1, y1, pdf_x1, pdf_y1)
103105
call normalize_to_pdf_coords(this%coord_ctx, x2, y2, pdf_x2, pdf_y2)
104106
call this%stream_writer%draw_vector_line(pdf_x1, pdf_y1, pdf_x2, pdf_y2)
@@ -151,6 +153,8 @@ subroutine draw_pdf_text_wrapper(this, x, y, text)
151153
integer :: processed_len
152154

153155
call process_latex_in_text(text, processed_text, processed_len)
156+
! Keep context in sync for text coordinate normalization as well
157+
call this%update_coord_context()
154158
call normalize_to_pdf_coords(this%coord_ctx, x, y, pdf_x, pdf_y)
155159
call draw_mixed_font_text(this%core_ctx, pdf_x, pdf_y, processed_text(1:processed_len))
156160
end subroutine draw_pdf_text_wrapper

src/backends/vector/fortplot_pdf_coordinate.f90

Lines changed: 20 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -39,49 +39,28 @@ subroutine normalize_to_pdf_coords(ctx, x, y, pdf_x, pdf_y)
3939
real(wp), intent(in) :: x, y
4040
real(wp), intent(out) :: pdf_x, pdf_y
4141
real(wp) :: x_range, y_range
42-
real(wp) :: x_scale, y_scale, common_scale
43-
real(wp) :: effective_width, effective_height
44-
real(wp) :: x_offset, y_offset
42+
real(wp) :: x_scale, y_scale
4543
real(wp), parameter :: EPSILON = 1.0e-10_wp
4644

4745
! Calculate data ranges with epsilon protection
4846
x_range = ctx%x_max - ctx%x_min
4947
y_range = ctx%y_max - ctx%y_min
5048

51-
! Handle degenerate cases first
49+
! Handle degenerate cases first (center in plot area)
5250
if (abs(x_range) < EPSILON) then
5351
pdf_x = real(ctx%plot_area%left, wp) + real(ctx%plot_area%width, wp) * 0.5_wp
52+
else
53+
x_scale = real(ctx%plot_area%width, wp) / x_range
54+
pdf_x = (x - ctx%x_min) * x_scale + real(ctx%plot_area%left, wp)
5455
end if
5556

5657
if (abs(y_range) < EPSILON) then
57-
pdf_y = real(ctx%plot_area%bottom, wp) + &
58-
real(ctx%plot_area%height, wp) * 0.5_wp
58+
pdf_y = real(ctx%plot_area%bottom, wp) + real(ctx%plot_area%height, wp) * 0.5_wp
59+
else
60+
y_scale = real(ctx%plot_area%height, wp) / y_range
61+
! PDF coordinates: Y=0 at bottom, direct mapping
62+
pdf_y = (y - ctx%y_min) * y_scale + real(ctx%plot_area%bottom, wp)
5963
end if
60-
61-
if (abs(x_range) < EPSILON .or. abs(y_range) < EPSILON) return
62-
63-
! Calculate potential scales for each axis
64-
x_scale = real(ctx%plot_area%width, wp) / x_range
65-
y_scale = real(ctx%plot_area%height, wp) / y_range
66-
67-
! Use the smaller scale to preserve aspect ratio
68-
common_scale = min(x_scale, y_scale)
69-
70-
! Calculate effective dimensions using common scale
71-
effective_width = x_range * common_scale
72-
effective_height = y_range * common_scale
73-
74-
! Center the plot within the plot area
75-
x_offset = (real(ctx%plot_area%width, wp) - effective_width) * 0.5_wp
76-
y_offset = (real(ctx%plot_area%height, wp) - effective_height) * 0.5_wp
77-
78-
! Transform coordinates with aspect ratio preservation
79-
pdf_x = (x - ctx%x_min) * common_scale + &
80-
real(ctx%plot_area%left, wp) + x_offset
81-
82-
! PDF coordinates: Y=0 at bottom, so transform data coordinates directly
83-
pdf_y = (y - ctx%y_min) * common_scale + &
84-
real(ctx%plot_area%bottom, wp) + y_offset
8564
end subroutine normalize_to_pdf_coords
8665

8766
real(wp) function pdf_get_width_scale(ctx) result(scale)
@@ -247,52 +226,33 @@ end subroutine pdf_render_ylabel
247226
subroutine safe_coordinate_transform(x, y, x_min, x_max, y_min, y_max, &
248227
plot_left, plot_width, plot_bottom, plot_height, &
249228
pdf_x, pdf_y)
250-
!! Safe coordinate transformation with aspect ratio preservation
251-
!! Updated to maintain correct aspect ratios like normalize_to_pdf_coords
229+
!! Safe coordinate transformation using independent x/y scales
252230
real(wp), intent(in) :: x, y
253231
real(wp), intent(in) :: x_min, x_max, y_min, y_max
254232
real(wp), intent(in) :: plot_left, plot_width, plot_bottom, plot_height
255233
real(wp), intent(out) :: pdf_x, pdf_y
256234
real(wp), parameter :: EPSILON = 1.0e-10_wp
257235
real(wp) :: x_range, y_range
258-
real(wp) :: x_scale, y_scale, common_scale
259-
real(wp) :: effective_width, effective_height
260-
real(wp) :: x_offset, y_offset
236+
real(wp) :: x_scale, y_scale
261237

262238
! Calculate ranges with epsilon protection
263239
x_range = x_max - x_min
264240
y_range = y_max - y_min
265241

266-
! Handle degenerate cases
242+
! Handle degenerate cases by centering
267243
if (abs(x_range) < EPSILON) then
268244
pdf_x = plot_left + plot_width * 0.5_wp
245+
else
246+
x_scale = plot_width / x_range
247+
pdf_x = (x - x_min) * x_scale + plot_left
269248
end if
270249

271250
if (abs(y_range) < EPSILON) then
272251
pdf_y = plot_bottom + plot_height * 0.5_wp
252+
else
253+
y_scale = plot_height / y_range
254+
pdf_y = (y - y_min) * y_scale + plot_bottom
273255
end if
274-
275-
if (abs(x_range) < EPSILON .or. abs(y_range) < EPSILON) return
276-
277-
! Calculate potential scales for each axis
278-
x_scale = plot_width / x_range
279-
y_scale = plot_height / y_range
280-
281-
! Use the smaller scale to preserve aspect ratio
282-
common_scale = min(x_scale, y_scale)
283-
284-
! Calculate effective dimensions using common scale
285-
effective_width = x_range * common_scale
286-
effective_height = y_range * common_scale
287-
288-
! Center the plot within the plot area
289-
x_offset = (plot_width - effective_width) * 0.5_wp
290-
y_offset = (plot_height - effective_height) * 0.5_wp
291-
292-
! Transform coordinates with aspect ratio preservation
293-
pdf_x = (x - x_min) * common_scale + plot_left + x_offset
294-
pdf_y = (y - y_min) * common_scale + plot_bottom + y_offset
295-
296256
end subroutine safe_coordinate_transform
297257

298-
end module fortplot_pdf_coordinate
258+
end module fortplot_pdf_coordinate

0 commit comments

Comments
 (0)