Skip to content

Commit 12478a5

Browse files
authored
fix: correct 3d axis tick orientation and avoid duplicate 2d labels (#1351)
## Summary - flip the 3D X-axis tick marks and labels so they render beneath the axis in device space - skip drawing the legacy 2D tick labels when 3D plots are active while still rendering the axis title/x/y labels ## Testing - make verify-artifacts ------ https://chatgpt.com/codex/tasks/task_e_68cd9f2942248324b0b3feb6167d67cd
1 parent 1b1421f commit 12478a5

File tree

2 files changed

+39
-13
lines changed

2 files changed

+39
-13
lines changed

src/backends/raster/fortplot_raster.f90

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module fortplot_raster
2020
use fortplot_raster_core, only: raster_image_t, create_raster_image, destroy_raster_image
2121
use fortplot_raster_axes, only: raster_draw_axes_and_labels, raster_render_ylabel, &
2222
raster_draw_axes_lines_and_ticks, raster_draw_axis_labels_only
23+
use fortplot_raster_labels, only: raster_draw_axis_labels
2324
use fortplot_raster_rendering, only: raster_fill_heatmap, raster_fill_quad, fill_triangle, &
2425
raster_render_legend_specialized, raster_calculate_legend_dimensions, &
2526
raster_set_legend_border_width, raster_calculate_legend_position, &
@@ -456,7 +457,8 @@ subroutine raster_draw_axes_and_labels_context(this, xscale, yscale, symlog_thre
456457
character(len=:), allocatable, intent(in), optional :: title, xlabel, ylabel
457458
real(wp), intent(in), optional :: z_min, z_max
458459
logical, intent(in) :: has_3d_plots
459-
460+
character(len=:), allocatable :: title_str, xlabel_str, ylabel_str
461+
460462
! Set color to black for axes and text
461463
call this%color(0.0_wp, 0.0_wp, 0.0_wp)
462464

@@ -465,12 +467,24 @@ subroutine raster_draw_axes_and_labels_context(this, xscale, yscale, symlog_thre
465467
call draw_3d_axes(this, x_min, x_max, y_min, y_max, &
466468
merge(z_min, 0.0_wp, present(z_min)), &
467469
merge(z_max, 1.0_wp, present(z_max)))
468-
! Draw title/xlabel/ylabel using existing raster helpers for labels only
470+
! Draw title/xlabel/ylabel without re-drawing 2D tick labels
469471
if (present(title) .or. present(xlabel) .or. present(ylabel)) then
470-
call raster_draw_axis_labels_only(this%raster, this%width, this%height, this%plot_area, &
471-
xscale, yscale, symlog_threshold, &
472-
x_min, x_max, y_min, y_max, &
473-
title, xlabel, ylabel)
472+
title_str = ""
473+
xlabel_str = ""
474+
ylabel_str = ""
475+
476+
if (present(title)) then
477+
if (allocated(title)) title_str = title
478+
end if
479+
if (present(xlabel)) then
480+
if (allocated(xlabel)) xlabel_str = xlabel
481+
end if
482+
if (present(ylabel)) then
483+
if (allocated(ylabel)) ylabel_str = ylabel
484+
end if
485+
486+
call raster_draw_axis_labels(this%raster, this%width, this%height, this%plot_area, &
487+
title_str, xlabel_str, ylabel_str)
474488
end if
475489
else
476490
! Delegate to standard 2D axes module

src/plotting/fortplot_3d_axes.f90

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,14 @@ subroutine draw_3d_axis_ticks_and_labels(ctx, corners_2d, x_min, x_max, y_min, y
226226
real(wp) :: x_range, y_range
227227
real(wp) :: tick_len_y, tick_len_x
228228
real(wp) :: pad_x, pad_y
229+
real(wp) :: tick_y_end, label_y_pos
230+
real(wp) :: y_span
229231
integer :: decimals_x, decimals_y, decimals_z
230232

231233
! Use fractions of the current data ranges for tick lengths and padding
232-
x_range = max(1.0e-12_wp, x_max - x_min)
233-
y_range = max(1.0e-12_wp, y_max - y_min)
234+
x_range = max(1.0e-12_wp, abs(x_max - x_min))
235+
y_span = y_max - y_min
236+
y_range = max(1.0e-12_wp, abs(y_span))
234237
tick_len_y = 0.02_wp * y_range ! vertical tick length (in data units)
235238
tick_len_x = 0.02_wp * x_range ! horizontal tick length (in data units)
236239
pad_x = 0.02_wp * x_range ! horizontal text padding (data units)
@@ -252,13 +255,22 @@ subroutine draw_3d_axis_ticks_and_labels(ctx, corners_2d, x_min, x_max, y_min, y
252255
! Interpolate position along edge
253256
x_pos = corners_2d(1,1) + (corners_2d(1,2) - corners_2d(1,1)) * real(i-1, wp) / real(n_ticks-1, wp)
254257
y_pos = corners_2d(2,1) + (corners_2d(2,2) - corners_2d(2,1)) * real(i-1, wp) / real(n_ticks-1, wp)
255-
256-
! Draw tick mark pointing down (in data units)
257-
call ctx%line(x_pos, y_pos, x_pos, y_pos + tick_len_y)
258-
258+
259+
! Determine downward direction in device space based on Y span sign
260+
if (y_span >= 0.0_wp) then
261+
tick_y_end = y_pos - tick_len_y
262+
label_y_pos = tick_y_end - pad_y
263+
else
264+
tick_y_end = y_pos + tick_len_y
265+
label_y_pos = tick_y_end + pad_y
266+
end if
267+
268+
! Draw tick mark pointing down in device space
269+
call ctx%line(x_pos, y_pos, x_pos, tick_y_end)
270+
259271
! Draw label using consistent decimal places across the axis
260272
label = format_tick_value_consistent(value, decimals_x)
261-
call render_text_to_ctx(ctx, x_pos - 0.5_wp*pad_x, y_pos + tick_len_y + pad_y, trim(adjustl(label)))
273+
call render_text_to_ctx(ctx, x_pos - 0.5_wp*pad_x, label_y_pos, trim(adjustl(label)))
262274
end do
263275

264276
! Y-axis ticks and labels (edge from corner 1 to corner 4)

0 commit comments

Comments
 (0)