fortplot_margins.f90 Source File


Source Code

module fortplot_margins
    !! Common margin and axis functionality for plotting backends
    !! 
    !! This module provides shared functionality for calculating margins,
    !! plot areas, and drawing axes across different backends (PNG, PDF, etc.)
    !! Follows DRY principle by centralizing common plotting layout logic.
    
    use, intrinsic :: iso_fortran_env, only: wp => real64
    use fortplot_layout, only: plot_margins_t, plot_area_t, calculate_plot_area
    use fortplot_ticks, only: calculate_tick_labels, format_tick_value, calculate_nice_axis_limits
    use fortplot_ticks, only: calculate_tick_labels_log, calculate_tick_labels_symlog
    implicit none
    
    private
    public :: plot_margins_t, plot_area_t, calculate_plot_area, draw_basic_axes_frame, get_axis_tick_positions
    
contains


    subroutine get_axis_tick_positions(plot_area, num_ticks_x, num_ticks_y, &
                                      x_positions, y_positions, actual_num_x, actual_num_y)
        !! Generate tick mark positions for basic axes
        type(plot_area_t), intent(in) :: plot_area
        integer, intent(in) :: num_ticks_x, num_ticks_y
        real(wp), intent(out) :: x_positions(:), y_positions(:)
        integer, intent(out) :: actual_num_x, actual_num_y
        
        real(wp) :: tick_spacing_x, tick_spacing_y
        integer :: i
        
        actual_num_x = min(num_ticks_x, size(x_positions))
        actual_num_y = min(num_ticks_y, size(y_positions))
        
        if (actual_num_x > 1) then
            tick_spacing_x = real(plot_area%width, wp) / real(actual_num_x - 1, wp)
            do i = 1, actual_num_x
                x_positions(i) = real(plot_area%left, wp) + real(i - 1, wp) * tick_spacing_x
            end do
        end if
        
        if (actual_num_y > 1) then
            tick_spacing_y = real(plot_area%height, wp) / real(actual_num_y - 1, wp)
            do i = 1, actual_num_y
                y_positions(i) = real(plot_area%bottom, wp) + real(i - 1, wp) * tick_spacing_y
            end do
        end if
    end subroutine get_axis_tick_positions

    subroutine draw_basic_axes_frame(plot_area, draw_line_proc)
        !! Draw basic rectangular axes frame
        !! Uses a procedure pointer to be backend-agnostic
        type(plot_area_t), intent(in) :: plot_area
        interface
            subroutine draw_line_proc(x1, y1, x2, y2)
                import :: wp
                real(wp), intent(in) :: x1, y1, x2, y2
            end subroutine
        end interface
        
        real(wp) :: left, right, top, bottom
        
        left = real(plot_area%left, wp)
        right = real(plot_area%left + plot_area%width, wp) 
        top = real(plot_area%bottom, wp)
        bottom = real(plot_area%bottom + plot_area%height, wp)
        
        ! Draw frame (rectangle)
        call draw_line_proc(left, top, right, top)        ! Top edge
        call draw_line_proc(left, bottom, right, bottom)  ! Bottom edge  
        call draw_line_proc(left, top, left, bottom)      ! Left edge
        call draw_line_proc(right, top, right, bottom)    ! Right edge
    end subroutine draw_basic_axes_frame
















end module fortplot_margins