module fortplot_figure_grid !! Figure grid functionality module !! !! Single Responsibility: Handle grid configuration and rendering !! Extracted from fortplot_figure_core to improve modularity use, intrinsic :: iso_fortran_env, only: wp => real64 use fortplot_context use fortplot_ascii, only: ascii_context use fortplot_axes, only: compute_scale_ticks use fortplot_scales, only: apply_scale_transform implicit none private public :: configure_grid, render_grid_lines contains subroutine configure_grid(grid_enabled, grid_which, grid_axis, grid_alpha, & grid_linestyle, enabled, which, axis, alpha, linestyle) !! Configure grid settings logical, intent(inout) :: grid_enabled character(len=10), intent(inout) :: grid_which character(len=1), intent(inout) :: grid_axis real(wp), intent(inout) :: grid_alpha character(len=10), intent(inout) :: grid_linestyle logical, intent(in), optional :: enabled character(len=*), intent(in), optional :: which, axis, linestyle real(wp), intent(in), optional :: alpha ! Handle boolean toggle syntax if (present(enabled)) then grid_enabled = enabled end if ! Handle string-based which parameter if (present(which)) then grid_which = which grid_enabled = .true. ! Implicitly enable grid end if ! Handle axis parameter with flexible input if (present(axis)) then select case(trim(axis)) case('x') grid_axis = 'x' case('y') grid_axis = 'y' case('both', 'b') grid_axis = 'b' case default grid_axis = 'b' end select grid_enabled = .true. ! Implicitly enable grid end if ! Handle alpha parameter if (present(alpha)) then grid_alpha = max(0.0_wp, min(1.0_wp, alpha)) grid_enabled = .true. ! Implicitly enable grid end if ! Handle linestyle parameter if (present(linestyle)) then grid_linestyle = linestyle grid_enabled = .true. ! Implicitly enable grid end if end subroutine configure_grid subroutine render_grid_lines(backend, grid_enabled, grid_which, grid_axis, & grid_alpha, width, height, margin_left, margin_right, & margin_bottom, margin_top, xscale, yscale, & symlog_threshold, x_min, x_max, y_min, y_max, & x_min_transformed, x_max_transformed, & y_min_transformed, y_max_transformed, grid_linestyle) !! Render grid lines on the figure class(plot_context), intent(inout) :: backend logical, intent(in) :: grid_enabled character(len=10), intent(in) :: grid_which character(len=1), intent(in) :: grid_axis real(wp), intent(in) :: grid_alpha integer, intent(in) :: width, height real(wp), intent(in) :: margin_left, margin_right, margin_bottom, margin_top character(len=*), intent(in) :: xscale, yscale real(wp), intent(in) :: symlog_threshold real(wp), intent(in) :: x_min, x_max, y_min, y_max real(wp), intent(in) :: x_min_transformed, x_max_transformed real(wp), intent(in) :: y_min_transformed, y_max_transformed character(len=*), intent(in) :: grid_linestyle real(wp) :: major_ticks(50) real(wp) :: tick_val, x1, y1, x2, y2, alpha_val integer :: i, num_ticks real(wp) :: grid_color(3) character(len=:), allocatable :: style real(wp) :: xmin_t, xmax_t, ymin_t, ymax_t if (.not. grid_enabled) return ! ASCII backend renders text plots where grid lines turn into noisy ! backgrounds, so skip grid rendering entirely for ASCII output. select type (backend) type is (ascii_context) return class default end select ! Set grid color (gray) and alpha (alpha currently backend-specific; kept for API parity) grid_color = [0.7_wp, 0.7_wp, 0.7_wp] alpha_val = max(0.0_wp, min(1.0_wp, grid_alpha)) ! Normalize transformed bounds to ensure proper ordering xmin_t = min(x_min_transformed, x_max_transformed) xmax_t = max(x_min_transformed, x_max_transformed) ymin_t = min(y_min_transformed, y_max_transformed) ymax_t = max(y_min_transformed, y_max_transformed) ! Apply grid styling once style = trim(grid_linestyle) if (len_trim(style) == 0) style = '-' call backend%color(grid_color(1), grid_color(2), grid_color(3)) call backend%set_line_style(style) ! Draw X-axis grid lines (vertical lines) if (grid_axis == 'x' .or. grid_axis == 'b') then ! Get major ticks for x-axis call compute_scale_ticks(xscale, x_min, x_max, & symlog_threshold, major_ticks, num_ticks) ! Draw major tick grid lines if (grid_which == 'major' .or. grid_which == 'both') then do i = 1, num_ticks tick_val = major_ticks(i) if (tick_val >= x_min .and. tick_val <= x_max) then ! Transform tick value to backend data coordinates tick_val = apply_scale_transform(tick_val, xscale, symlog_threshold) ! In backend data coordinates, a vertical grid line is x = tick_val x1 = tick_val y1 = ymin_t x2 = tick_val y2 = ymax_t ! Draw grid line in backend coordinate space call backend%line(x1, y1, x2, y2) end if end do end if end if ! Draw Y-axis grid lines (horizontal lines) if (grid_axis == 'y' .or. grid_axis == 'b') then ! Get major ticks for y-axis call compute_scale_ticks(yscale, y_min, y_max, & symlog_threshold, major_ticks, num_ticks) ! Draw major tick grid lines if (grid_which == 'major' .or. grid_which == 'both') then do i = 1, num_ticks tick_val = major_ticks(i) if (tick_val >= y_min .and. tick_val <= y_max) then ! Transform tick value to backend data coordinates tick_val = apply_scale_transform(tick_val, yscale, symlog_threshold) ! In backend data coordinates, a horizontal grid line is y = tick_val x1 = xmin_t y1 = tick_val x2 = xmax_t y2 = tick_val ! Draw grid line in backend coordinate space call backend%line(x1, y1, x2, y2) end if end do end if end if ! Restore default solid line style to avoid leaking style changes call backend%set_line_style('-') end subroutine render_grid_lines end module fortplot_figure_grid