module fortplot_raster_ticks !! Raster tick marks and tick labels rendering functionality !! Extracted from fortplot_raster_axes.f90 for single responsibility principle use fortplot_constants, only: TICK_MARK_LENGTH use fortplot_text_rendering, only: render_text_to_image, calculate_text_width, calculate_text_height use fortplot_latex_parser, only: process_latex_in_text use fortplot_unicode, only: escape_unicode_for_raster use fortplot_text_helpers, only: prepare_mathtext_if_needed use fortplot_margins, only: plot_area_t use fortplot_raster_line_styles, only: draw_styled_line use fortplot_raster_core, only: raster_image_t use fortplot_scales, only: apply_scale_transform use, intrinsic :: iso_fortran_env, only: wp => real64 implicit none private public :: raster_draw_x_axis_ticks public :: raster_draw_y_axis_ticks public :: raster_draw_x_axis_tick_marks_only public :: raster_draw_y_axis_tick_marks_only public :: raster_draw_x_axis_tick_labels_only public :: raster_draw_y_axis_tick_labels_only public :: raster_draw_y_axis_ticks_right public :: raster_draw_y_axis_tick_marks_only_right public :: raster_draw_y_axis_tick_labels_only_right public :: raster_draw_x_axis_ticks_top public :: raster_draw_x_axis_tick_marks_only_top public :: raster_draw_x_axis_tick_labels_only_top public :: last_y_tick_max_width public :: last_y_tick_max_width_right public :: last_x_tick_max_height_top public :: X_TICK_LABEL_PAD, Y_TICK_LABEL_RIGHT_PAD public :: Y_TICK_LABEL_LEFT_PAD, X_TICK_LABEL_TOP_PAD public :: compute_non_overlapping_mask ! Local spacing parameters for raster tick labels (pixels) ! X tick labels are positioned X_TICK_LABEL_PAD pixels below the tick end ! Y tick labels are right-aligned with a gap of Y_TICK_LABEL_RIGHT_PAD from the tick end integer, parameter :: X_TICK_LABEL_PAD = 20 integer, parameter :: Y_TICK_LABEL_RIGHT_PAD = 10 integer, parameter :: Y_TICK_LABEL_LEFT_PAD = 10 integer, parameter :: X_TICK_LABEL_TOP_PAD = 20 ! Cache the maximum Y-tick label width measured during the last ! raster_draw_y_axis_ticks() call so ylabel placement can avoid overlap integer :: last_y_tick_max_width = 0 integer :: last_y_tick_max_width_right = 0 integer :: last_x_tick_max_height_top = 0 contains subroutine raster_draw_x_axis_ticks(raster, width, height, plot_area, & xscale, symlog_threshold, xticks, xtick_labels, xtick_colors, x_min, x_max) !! Draw x-axis tick marks and labels type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: xticks(:) character(len=*), intent(in) :: xtick_labels(:) integer, intent(in) :: xtick_colors(:, :) real(wp), intent(in) :: x_min, x_max call raster_draw_x_axis_tick_marks_only(raster, width, height, plot_area, & xscale, symlog_threshold, xticks, xtick_colors, x_min, x_max) call raster_draw_x_axis_tick_labels_only(raster, width, height, plot_area, & xscale, symlog_threshold, xticks, xtick_labels, x_min, x_max) end subroutine raster_draw_x_axis_ticks subroutine raster_draw_y_axis_ticks(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_labels, ytick_colors, y_min, y_max) !! Draw y-axis tick marks and labels type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: yticks(:) character(len=*), intent(in) :: ytick_labels(:) integer, intent(in) :: ytick_colors(:, :) real(wp), intent(in) :: y_min, y_max integer :: j integer :: label_width, label_height ! Track maximum label width for ylabel positioning last_y_tick_max_width = 0 do j = 1, size(yticks) label_width = calculate_text_width(trim(ytick_labels(j))) last_y_tick_max_width = max(last_y_tick_max_width, label_width) end do call raster_draw_y_axis_tick_marks_only(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_colors, y_min, y_max) call raster_draw_y_axis_tick_labels_only(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_labels, y_min, y_max) end subroutine raster_draw_y_axis_ticks subroutine raster_draw_x_axis_tick_marks_only(raster, width, height, plot_area, & xscale, symlog_threshold, xticks, xtick_colors, x_min, x_max) !! Draw only x-axis tick marks (no labels) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: xticks(:) integer, intent(in) :: xtick_colors(:, :) real(wp), intent(in) :: x_min, x_max integer :: tick_x, tick_top, tick_bottom, j real(wp) :: min_t, max_t, tick_t real(wp) :: dummy_pattern(1), pattern_dist ! Draw x-axis tick marks min_t = apply_scale_transform(x_min, xscale, symlog_threshold) max_t = apply_scale_transform(x_max, xscale, symlog_threshold) dummy_pattern = 0.0_wp pattern_dist = 0.0_wp do j = 1, size(xticks) tick_t = apply_scale_transform(xticks(j), xscale, symlog_threshold) if (max_t > min_t) then tick_x = plot_area%left + int((tick_t - min_t) / (max_t - min_t) * plot_area%width) else tick_x = plot_area%left end if tick_top = plot_area%bottom + plot_area%height tick_bottom = min(height, tick_top + TICK_MARK_LENGTH) call draw_styled_line(raster%image_data, width, height, & real(tick_x, wp), real(tick_top, wp), real(tick_x, wp), real(tick_bottom, wp), & real(xtick_colors(1,j),wp)/255.0_wp, real(xtick_colors(2,j),wp)/255.0_wp, & real(xtick_colors(3,j),wp)/255.0_wp, 1.0_wp, 'solid', dummy_pattern, 0, 0.0_wp, pattern_dist) end do end subroutine raster_draw_x_axis_tick_marks_only subroutine raster_draw_y_axis_tick_marks_only(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_colors, y_min, y_max) !! Draw only y-axis tick marks (no labels) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: yticks(:) integer, intent(in) :: ytick_colors(:, :) real(wp), intent(in) :: y_min, y_max integer :: tick_y, tick_left, tick_right, j real(wp) :: min_t, max_t, tick_t real(wp) :: dummy_pattern(1), pattern_dist ! Draw y-axis tick marks min_t = apply_scale_transform(y_min, yscale, symlog_threshold) max_t = apply_scale_transform(y_max, yscale, symlog_threshold) dummy_pattern = 0.0_wp pattern_dist = 0.0_wp do j = 1, size(yticks) tick_t = apply_scale_transform(yticks(j), yscale, symlog_threshold) if (max_t > min_t) then tick_y = plot_area%bottom + plot_area%height - int((tick_t - min_t) / (max_t - min_t) * & plot_area%height) else tick_y = plot_area%bottom end if tick_left = max(1, plot_area%left - TICK_MARK_LENGTH) tick_right = plot_area%left call draw_styled_line(raster%image_data, width, height, & real(tick_left, wp), real(tick_y, wp), real(tick_right, wp), real(tick_y, wp), & real(ytick_colors(1,j),wp)/255.0_wp, real(ytick_colors(2,j),wp)/255.0_wp, & real(ytick_colors(3,j),wp)/255.0_wp, 1.0_wp, 'solid', dummy_pattern, 0, 0.0_wp, pattern_dist) end do end subroutine raster_draw_y_axis_tick_marks_only subroutine raster_draw_x_axis_tick_labels_only(raster, width, height, plot_area, & xscale, symlog_threshold, xticks, xtick_labels, x_min, x_max) !! Draw only x-axis tick labels (no marks) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: xticks(:) character(len=*), intent(in) :: xtick_labels(:) real(wp), intent(in) :: x_min, x_max logical, dimension(size(xticks)) :: visibility_mask integer :: tick_x, label_x, label_y, j integer :: label_width, label_height real(wp) :: min_t, max_t, tick_t character(len=500) :: processed_text character(len=600) :: math_ready character(len=600) :: escaped_text integer :: processed_len, math_len ! Draw x-axis tick labels with overlap prevention min_t = apply_scale_transform(x_min, xscale, symlog_threshold) max_t = apply_scale_transform(x_max, xscale, symlog_threshold) ! Compute which labels can be drawn without overlapping call compute_non_overlapping_mask(xticks, xtick_labels, x_min, x_max, xscale, & symlog_threshold, plot_area, visibility_mask) do j = 1, size(xticks) if (.not. visibility_mask(j)) cycle ! Skip overlapping labels tick_t = apply_scale_transform(xticks(j), xscale, symlog_threshold) if (max_t > min_t) then tick_x = plot_area%left + int((tick_t - min_t) / (max_t - min_t) * plot_area%width) else tick_x = plot_area%left end if ! Process LaTeX (allocation handled internally) call process_latex_in_text(trim(xtick_labels(j)), processed_text, processed_len) call prepare_mathtext_if_needed(processed_text(1:processed_len), math_ready, math_len) call escape_unicode_for_raster(math_ready(1:math_len), escaped_text) label_width = calculate_text_width(trim(escaped_text)) label_height = calculate_text_height(trim(escaped_text)) label_x = tick_x - label_width / 2 ! Center horizontally at tick label_y = plot_area%bottom + plot_area%height + X_TICK_LABEL_PAD call render_text_to_image(raster%image_data, width, height, & label_x, label_y, trim(escaped_text), 0_1, 0_1, 0_1) end do end subroutine raster_draw_x_axis_tick_labels_only subroutine raster_draw_y_axis_tick_labels_only(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_labels, y_min, y_max) !! Draw only y-axis tick labels (no marks) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: yticks(:) character(len=*), intent(in) :: ytick_labels(:) real(wp), intent(in) :: y_min, y_max integer :: tick_y, label_x, label_y, j integer :: label_width, label_height real(wp) :: min_t, max_t, tick_t character(len=500) :: processed_text character(len=600) :: math_ready character(len=600) :: escaped_text integer :: processed_len, math_len ! Draw y-axis tick labels min_t = apply_scale_transform(y_min, yscale, symlog_threshold) max_t = apply_scale_transform(y_max, yscale, symlog_threshold) do j = 1, size(yticks) tick_t = apply_scale_transform(yticks(j), yscale, symlog_threshold) if (max_t > min_t) then tick_y = plot_area%bottom + plot_area%height - int((tick_t - min_t) / (max_t - min_t) * & plot_area%height) else tick_y = plot_area%bottom end if ! Process LaTeX (allocation handled internally) call process_latex_in_text(trim(ytick_labels(j)), processed_text, processed_len) call prepare_mathtext_if_needed(processed_text(1:processed_len), math_ready, math_len) call escape_unicode_for_raster(math_ready(1:math_len), escaped_text) label_width = calculate_text_width(trim(escaped_text)) label_height = calculate_text_height(trim(escaped_text)) ! If height calculation fails, use a default if (label_height <= 0) label_height = 12 ! Right-align with a small gap from the tick end label_x = plot_area%left - Y_TICK_LABEL_RIGHT_PAD - label_width ! Center vertically at tick position - move DOWN for better alignment label_y = tick_y + label_height / 4 ! Move down from tick for better visual alignment call render_text_to_image(raster%image_data, width, height, & label_x, label_y, trim(escaped_text), 0_1, 0_1, 0_1) end do end subroutine raster_draw_y_axis_tick_labels_only subroutine raster_draw_y_axis_ticks_right(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_labels, ytick_colors, y_min, y_max) !! Draw y-axis tick marks and labels along the right side type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: yticks(:) character(len=*), intent(in) :: ytick_labels(:) integer, intent(in) :: ytick_colors(:, :) real(wp), intent(in) :: y_min, y_max integer :: j integer :: label_width last_y_tick_max_width_right = 0 do j = 1, size(yticks) label_width = calculate_text_width(trim(ytick_labels(j))) last_y_tick_max_width_right = max(last_y_tick_max_width_right, label_width) end do call raster_draw_y_axis_tick_marks_only_right(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_colors, y_min, y_max) call raster_draw_y_axis_tick_labels_only_right(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_labels, y_min, y_max) end subroutine raster_draw_y_axis_ticks_right subroutine raster_draw_y_axis_tick_marks_only_right(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_colors, y_min, y_max) !! Draw y-axis tick marks on the right side (no labels) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: yticks(:) integer, intent(in) :: ytick_colors(:, :) real(wp), intent(in) :: y_min, y_max integer :: tick_y, tick_left, tick_right, j real(wp) :: min_t, max_t, tick_t real(wp) :: dummy_pattern(1), pattern_dist min_t = apply_scale_transform(y_min, yscale, symlog_threshold) max_t = apply_scale_transform(y_max, yscale, symlog_threshold) dummy_pattern = 0.0_wp pattern_dist = 0.0_wp do j = 1, size(yticks) tick_t = apply_scale_transform(yticks(j), yscale, symlog_threshold) if (max_t > min_t) then tick_y = plot_area%bottom + plot_area%height - int((tick_t - min_t) / (max_t - min_t) * & plot_area%height) else tick_y = plot_area%bottom end if tick_left = plot_area%left + plot_area%width tick_right = min(width, tick_left + TICK_MARK_LENGTH) call draw_styled_line(raster%image_data, width, height, & real(tick_left, wp), real(tick_y, wp), real(tick_right, wp), real(tick_y, wp), & real(ytick_colors(1,j),wp)/255.0_wp, real(ytick_colors(2,j),wp)/255.0_wp, & real(ytick_colors(3,j),wp)/255.0_wp, 1.0_wp, 'solid', dummy_pattern, 0, 0.0_wp, pattern_dist) end do end subroutine raster_draw_y_axis_tick_marks_only_right subroutine raster_draw_y_axis_tick_labels_only_right(raster, width, height, plot_area, yscale, symlog_threshold, & yticks, ytick_labels, y_min, y_max) !! Draw y-axis tick labels on the right side (no marks) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: yticks(:) character(len=*), intent(in) :: ytick_labels(:) real(wp), intent(in) :: y_min, y_max integer :: tick_y, label_x, label_y, j integer :: label_width, label_height real(wp) :: min_t, max_t, tick_t character(len=500) :: processed_text character(len=600) :: math_ready character(len=600) :: escaped_text integer :: processed_len, math_len min_t = apply_scale_transform(y_min, yscale, symlog_threshold) max_t = apply_scale_transform(y_max, yscale, symlog_threshold) do j = 1, size(yticks) tick_t = apply_scale_transform(yticks(j), yscale, symlog_threshold) if (max_t > min_t) then tick_y = plot_area%bottom + plot_area%height - int((tick_t - min_t) / (max_t - min_t) * & plot_area%height) else tick_y = plot_area%bottom end if call process_latex_in_text(trim(ytick_labels(j)), processed_text, processed_len) call prepare_mathtext_if_needed(processed_text(1:processed_len), math_ready, math_len) call escape_unicode_for_raster(math_ready(1:math_len), escaped_text) label_width = calculate_text_width(trim(escaped_text)) label_height = calculate_text_height(trim(escaped_text)) if (label_height <= 0) label_height = 12 label_x = plot_area%left + plot_area%width + Y_TICK_LABEL_LEFT_PAD label_y = tick_y + label_height / 4 call render_text_to_image(raster%image_data, width, height, & label_x, label_y, trim(escaped_text), 0_1, 0_1, 0_1) end do end subroutine raster_draw_y_axis_tick_labels_only_right subroutine raster_draw_x_axis_ticks_top(raster, width, height, plot_area, xscale, symlog_threshold, & xticks, xtick_labels, xtick_colors, x_min, x_max) !! Draw x-axis tick marks and labels along the top side type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: xticks(:) character(len=*), intent(in) :: xtick_labels(:) integer, intent(in) :: xtick_colors(:, :) real(wp), intent(in) :: x_min, x_max integer :: j integer :: label_height last_x_tick_max_height_top = 0 do j = 1, size(xticks) label_height = calculate_text_height(trim(xtick_labels(j))) last_x_tick_max_height_top = max(last_x_tick_max_height_top, label_height) end do call raster_draw_x_axis_tick_marks_only_top(raster, width, height, plot_area, xscale, symlog_threshold, & xticks, xtick_colors, x_min, x_max) call raster_draw_x_axis_tick_labels_only_top(raster, width, height, plot_area, xscale, symlog_threshold, & xticks, xtick_labels, x_min, x_max) end subroutine raster_draw_x_axis_ticks_top subroutine raster_draw_x_axis_tick_marks_only_top(raster, width, height, plot_area, & xscale, symlog_threshold, xticks, xtick_colors, x_min, x_max) !! Draw x-axis tick marks on the top side (no labels) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: xticks(:) integer, intent(in) :: xtick_colors(:, :) real(wp), intent(in) :: x_min, x_max integer :: tick_x, tick_top, tick_bottom, j real(wp) :: min_t, max_t, tick_t real(wp) :: dummy_pattern(1), pattern_dist min_t = apply_scale_transform(x_min, xscale, symlog_threshold) max_t = apply_scale_transform(x_max, xscale, symlog_threshold) dummy_pattern = 0.0_wp pattern_dist = 0.0_wp do j = 1, size(xticks) tick_t = apply_scale_transform(xticks(j), xscale, symlog_threshold) if (max_t > min_t) then tick_x = plot_area%left + int((tick_t - min_t) / (max_t - min_t) * plot_area%width) else tick_x = plot_area%left end if tick_top = max(1, plot_area%bottom - TICK_MARK_LENGTH) tick_bottom = plot_area%bottom call draw_styled_line(raster%image_data, width, height, & real(tick_x, wp), real(tick_top, wp), real(tick_x, wp), real(tick_bottom, wp), & real(xtick_colors(1,j),wp)/255.0_wp, real(xtick_colors(2,j),wp)/255.0_wp, & real(xtick_colors(3,j),wp)/255.0_wp, 1.0_wp, 'solid', dummy_pattern, 0, 0.0_wp, pattern_dist) end do end subroutine raster_draw_x_axis_tick_marks_only_top subroutine raster_draw_x_axis_tick_labels_only_top(raster, width, height, plot_area, xscale, symlog_threshold, & xticks, xtick_labels, x_min, x_max) !! Draw x-axis tick labels on the top side (no marks) type(raster_image_t), intent(inout) :: raster integer, intent(in) :: width, height type(plot_area_t), intent(in) :: plot_area character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: xticks(:) character(len=*), intent(in) :: xtick_labels(:) real(wp), intent(in) :: x_min, x_max integer :: tick_x, label_x, label_y, j integer :: label_width, label_height real(wp) :: min_t, max_t, tick_t character(len=500) :: processed_text character(len=600) :: math_ready character(len=600) :: escaped_text integer :: processed_len, math_len min_t = apply_scale_transform(x_min, xscale, symlog_threshold) max_t = apply_scale_transform(x_max, xscale, symlog_threshold) do j = 1, size(xticks) tick_t = apply_scale_transform(xticks(j), xscale, symlog_threshold) if (max_t > min_t) then tick_x = plot_area%left + int((tick_t - min_t) / (max_t - min_t) * plot_area%width) else tick_x = plot_area%left end if call process_latex_in_text(trim(xtick_labels(j)), processed_text, processed_len) call prepare_mathtext_if_needed(processed_text(1:processed_len), math_ready, math_len) call escape_unicode_for_raster(math_ready(1:math_len), escaped_text) label_width = calculate_text_width(trim(escaped_text)) label_height = calculate_text_height(trim(escaped_text)) if (label_height <= 0) label_height = 12 label_x = tick_x - label_width / 2 label_y = max(1, plot_area%bottom - X_TICK_LABEL_TOP_PAD - label_height) call render_text_to_image(raster%image_data, width, height, & label_x, label_y, trim(escaped_text), 0_1, 0_1, 0_1) end do end subroutine raster_draw_x_axis_tick_labels_only_top subroutine compute_non_overlapping_mask(xticks, xtick_labels, x_min, x_max, xscale, & symlog_threshold, plot_area, visibility_mask) !! Compute which x-axis tick labels can be drawn without overlapping !! Always shows first and last labels, hides overlapping ones in between real(wp), intent(in) :: xticks(:) character(len=*), intent(in) :: xtick_labels(:) real(wp), intent(in) :: x_min, x_max character(len=*), intent(in) :: xscale real(wp), intent(in) :: symlog_threshold type(plot_area_t), intent(in) :: plot_area logical, intent(out) :: visibility_mask(size(xticks)) integer :: j, n integer, allocatable :: label_lefts(:), label_rights(:) real(wp) :: min_t, max_t, tick_t integer :: tick_x, label_width character(len=500) :: processed_text, escaped_text integer :: processed_len integer :: min_gap integer :: last_visible_right n = size(xticks) if (n == 0) then return end if ! Minimum gap between labels (pixels) - increased for better readability min_gap = 8 allocate(label_lefts(n), label_rights(n)) ! Compute transformed bounds min_t = apply_scale_transform(x_min, xscale, symlog_threshold) max_t = apply_scale_transform(x_max, xscale, symlog_threshold) ! Calculate left and right edges of each label do j = 1, n tick_t = apply_scale_transform(xticks(j), xscale, symlog_threshold) if (max_t > min_t) then tick_x = plot_area%left + int((tick_t - min_t) / (max_t - min_t) * plot_area%width) else tick_x = plot_area%left end if ! Process LaTeX and calculate width call process_latex_in_text(trim(xtick_labels(j)), processed_text, processed_len) call escape_unicode_for_raster(processed_text(1:processed_len), escaped_text) label_width = calculate_text_width(trim(escaped_text)) ! Store label bounds (centered at tick) label_lefts(j) = tick_x - label_width / 2 label_rights(j) = tick_x + label_width / 2 end do ! Initialize all labels as invisible visibility_mask = .false. ! Always show first label if (n >= 1) then visibility_mask(1) = .true. last_visible_right = label_rights(1) end if ! Check middle labels do j = 2, n-1 if (label_lefts(j) >= last_visible_right + min_gap) then ! This label doesn't overlap, show it visibility_mask(j) = .true. last_visible_right = label_rights(j) end if end do ! Always try to show last label if it doesn't overlap if (n >= 2) then if (.not. visibility_mask(n)) then if (label_lefts(n) >= last_visible_right + min_gap) then visibility_mask(n) = .true. end if end if end if deallocate(label_lefts, label_rights) end subroutine compute_non_overlapping_mask end module fortplot_raster_ticks