fortplot_figure_core_operations.f90 Source File


Source Code

module fortplot_figure_core_operations
    !! Core operations implementations extracted from fortplot_figure_core
    !!
    !! This module contains the actual implementations of core figure operations
    !! that were previously inline procedures in the main core module.
    !!
    !! EXTRACTED OPERATIONS:
    !! - initialize: Figure initialization with backend setup
    !! - add_plot: Basic line plotting functionality
    !! - add_contour: Contour plot creation
    !! - add_contour_filled: Filled contour plots
    !! - add_pcolormesh: Pseudocolor mesh plotting
    !! - streamplot: Streamline visualization
    !! - savefig variants: File output operations
    !! - show: Figure display operations

    use, intrinsic :: iso_fortran_env, only: wp => real64
    use fortplot_context
    use fortplot_annotations, only: text_annotation_t
    use fortplot_plot_data, only: plot_data_t, arrow_data_t, subplot_data_t
    use fortplot_figure_initialization, only: figure_state_t, ensure_figure_storage
    use fortplot_figure_operations
    use fortplot_figure_management
    use fortplot_figure_core_ranges, only: update_data_ranges_figure, &
                                           update_data_ranges_pcolormesh_figure
    use fortplot_figure_quiver, only: quiver_figure
    implicit none

    private
    public :: core_initialize, core_add_plot, core_add_contour, core_add_contour_filled
    public :: core_add_surface, core_add_pcolormesh, core_add_fill_between, core_add_pie
    public :: core_streamplot, core_quiver, core_savefig, core_savefig_with_status
    public :: core_show

contains

    subroutine core_initialize(state, plots, streamlines, subplots_array, &
                               subplot_rows, &
                               subplot_cols, current_subplot, title, xlabel, ylabel, &
                               plot_count, width, height, backend, dpi)
        type(figure_state_t), intent(inout) :: state
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(plot_data_t), allocatable, intent(inout) :: streamlines(:)
        type(subplot_data_t), allocatable, intent(inout) :: subplots_array(:, :)
        integer, intent(inout) :: subplot_rows, subplot_cols, &
                                  current_subplot, plot_count
        character(len=:), allocatable, intent(inout) :: title, xlabel, ylabel
        integer, intent(in), optional :: width, height
        character(len=*), intent(in), optional :: backend
        real(wp), intent(in), optional :: dpi

        call figure_initialize(state, plots, streamlines, subplots_array, &
                               subplot_rows, &
                               subplot_cols, current_subplot, title, xlabel, ylabel, &
                               plot_count, width, height, backend, dpi)
    end subroutine core_initialize

    subroutine core_add_plot(plots, state, x, y, label, linestyle, color, plot_count)
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: x(:), y(:)
        character(len=*), intent(in), optional :: label, linestyle
        real(wp), intent(in), optional :: color(3)
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_plot_operation(plots, state, x, y, label, linestyle, color)
        plot_count = state%plot_count
        call update_data_ranges_figure(plots, state, state%plot_count)
    end subroutine core_add_plot

    subroutine core_add_contour(plots, state, x_grid, y_grid, z_grid, levels, label, &
                                plot_count)
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: x_grid(:), y_grid(:), z_grid(:, :)
        real(wp), intent(in), optional :: levels(:)
        character(len=*), intent(in), optional :: label
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_contour_operation(plots, state, x_grid, y_grid, z_grid, &
                                          levels, label)
        plot_count = state%plot_count
        call update_data_ranges_figure(plots, state, state%plot_count)
    end subroutine core_add_contour

    subroutine core_add_contour_filled(plots, state, x_grid, y_grid, z_grid, levels, &
                                       cmap, show_colorbar, label, colormap, plot_count)
        !! Add a filled contour plot to the figure
        !!
        !! `cmap` is the matplotlib-canonical keyword; `colormap` is a
        !! backward-compatible alias.
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: x_grid(:), y_grid(:), z_grid(:, :)
        real(wp), intent(in), optional :: levels(:)
        character(len=*), intent(in), optional :: cmap, label, colormap
        logical, intent(in), optional :: show_colorbar
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_contour_filled_operation(plots, state, x_grid, y_grid, z_grid, &
                                                 levels=levels, cmap=cmap, &
                                                 show_colorbar=show_colorbar, label=label, &
                                                 colormap=colormap)
        plot_count = state%plot_count
        call update_data_ranges_figure(plots, state, state%plot_count)
    end subroutine core_add_contour_filled

    subroutine core_add_surface(plots, state, x_grid, y_grid, z_grid, label, cmap, &
                                show_colorbar, alpha, edgecolor, linewidth, filled, &
                                plot_count, colormap)
        !! Add a 3D surface plot to the figure
        !!
        !! `cmap` is the matplotlib-canonical keyword; `colormap` is a
        !! backward-compatible alias.
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: x_grid(:), y_grid(:), z_grid(:, :)
        character(len=*), intent(in), optional :: label, cmap, colormap
        logical, intent(in), optional :: show_colorbar, filled
        real(wp), intent(in), optional :: alpha, linewidth
        real(wp), intent(in), optional :: edgecolor(3)
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_surface_operation(plots, state, x_grid, y_grid, z_grid, &
                                          label=label, cmap=cmap, &
                                          show_colorbar=show_colorbar, alpha=alpha, &
                                          edgecolor=edgecolor, linewidth=linewidth, &
                                          filled=filled, colormap=colormap)
        plot_count = state%plot_count
        call update_data_ranges_figure(plots, state, state%plot_count)
    end subroutine core_add_surface

    subroutine core_add_pcolormesh(plots, state, x, y, c, cmap, vmin, vmax, &
                                   edgecolors, linewidths, plot_count, colormap)
        !! Add a pcolormesh plot to the figure
        !!
        !! `cmap` is the matplotlib-canonical keyword; `colormap` is a
        !! backward-compatible alias.
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: x(:), y(:), c(:, :)
        character(len=*), intent(in), optional :: cmap, colormap
        real(wp), intent(in), optional :: vmin, vmax
        real(wp), intent(in), optional :: edgecolors(3)
        real(wp), intent(in), optional :: linewidths
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_pcolormesh_operation(plots, state, x, y, c, cmap=cmap, &
                                             vmin=vmin, vmax=vmax, &
                                             edgecolors=edgecolors, linewidths=linewidths, &
                                             colormap=colormap)
        plot_count = state%plot_count
        call update_data_ranges_pcolormesh_figure(plots, state, state%plot_count)
    end subroutine core_add_pcolormesh

    subroutine core_add_fill_between(plots, state, x, upper, lower, mask, &
                                     color_string, alpha, &
                                     plot_count)
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: x(:)
        real(wp), contiguous, intent(in) :: upper(:)
        real(wp), contiguous, intent(in) :: lower(:)
        logical, intent(in), optional :: mask(:)
        character(len=*), intent(in), optional :: color_string
        real(wp), intent(in), optional :: alpha
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_fill_between_operation(plots, state, x, upper, lower, mask, &
                                               color_string, alpha)
        plot_count = state%plot_count
        call update_data_ranges_figure(plots, state, state%plot_count)
    end subroutine core_add_fill_between

    subroutine core_add_pie(plots, state, values, labels, autopct, startangle, colors, &
                            explode, plot_count)
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        real(wp), contiguous, intent(in) :: values(:)
        character(len=*), intent(in), optional :: labels(:)
        character(len=*), intent(in), optional :: autopct
        real(wp), intent(in), optional :: startangle
        character(len=*), intent(in), optional :: colors(:)
        real(wp), intent(in), optional :: explode(:)
        integer, intent(inout) :: plot_count

        call ensure_figure_storage(plots, state)
        call figure_add_pie_operation(plots, state, values, labels, startangle, &
                                      colors, explode, autopct)
        plot_count = state%plot_count
        call update_data_ranges_figure(plots, state, state%plot_count)
    end subroutine core_add_pie

  subroutine core_streamplot(plots, state, plot_count, x, y, u, v, &
                                density, color, &
                                linewidth, rtol, atol, max_time, &
                                arrowsize, arrowstyle)
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        integer, intent(inout) :: plot_count
        real(wp), contiguous, intent(in) :: x(:), y(:), u(:, :), v(:, :)
        real(wp), intent(in), optional :: density
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: linewidth, rtol, atol, max_time
        real(wp), intent(in), optional :: arrowsize
        character(len=*), intent(in), optional :: arrowstyle

        call ensure_figure_storage(plots, state)
        call figure_streamplot_operation(plots, state, plot_count, x, y, u, v, &
                                         density, color, linewidth, rtol, &
                                         atol, max_time, &
                                         arrowsize, arrowstyle)
        ! Sync state%plot_count with plot_count (streamplot updates plot_count directly)
        state%plot_count = plot_count
    end subroutine core_streamplot

    subroutine core_quiver(plots, state, plot_count, x, y, u, v, scale, color, &
                           width, headwidth, headlength, units, pivot, scale_units, &
                           angles, colormap, alpha)
        !! Add quiver plot (discrete vector arrows) to figure
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        type(figure_state_t), intent(inout) :: state
        integer, intent(inout) :: plot_count
        real(wp), contiguous, intent(in) :: x(:), y(:), u(:), v(:)
        real(wp), intent(in), optional :: scale
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: width, headwidth, headlength
        character(len=*), intent(in), optional :: units, pivot, scale_units, angles
        character(len=*), intent(in), optional :: colormap
        real(wp), intent(in), optional :: alpha

        call ensure_figure_storage(plots, state)
        call quiver_figure(plots, state, plot_count, x, y, u, v, scale, color, &
                           width, headwidth, headlength, units, pivot, scale_units, &
                           angles=angles, colormap=colormap, alpha=alpha)
        call update_data_ranges_figure(plots, state, plot_count)
    end subroutine core_quiver

    subroutine core_savefig(state, plots, plot_count, filename, blocking, &
                            annotations, annotation_count, subplots_array, &
                            subplot_rows, subplot_cols)
        type(figure_state_t), intent(inout) :: state
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        integer, intent(in) :: plot_count
        character(len=*), intent(in) :: filename
        logical, intent(in), optional :: blocking
        type(text_annotation_t), allocatable, intent(inout) :: annotations(:)
        integer, intent(in) :: annotation_count
        type(subplot_data_t), intent(in), optional :: subplots_array(:, :)
        integer, intent(in), optional :: subplot_rows, subplot_cols

        call ensure_figure_storage(plots, state)
        call figure_savefig(state, plots, plot_count, filename, blocking, &
                            annotations, annotation_count, subplots_array, &
                            subplot_rows, subplot_cols)
    end subroutine core_savefig

    subroutine core_savefig_with_status(state, plots, plot_count, filename, status, &
                                        blocking, &
                                        annotations, annotation_count, subplots_array, &
                                        subplot_rows, subplot_cols)
        type(figure_state_t), intent(inout) :: state
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        integer, intent(in) :: plot_count
        character(len=*), intent(in) :: filename
        integer, intent(out) :: status
        logical, intent(in), optional :: blocking
        type(text_annotation_t), allocatable, intent(inout) :: annotations(:)
        integer, intent(in) :: annotation_count
        type(subplot_data_t), intent(in), optional :: subplots_array(:, :)
        integer, intent(in), optional :: subplot_rows, subplot_cols

        call ensure_figure_storage(plots, state)
        call figure_savefig_with_status(state, plots, plot_count, filename, status, &
                                        blocking, &
                                        annotations, annotation_count, subplots_array, &
                                        subplot_rows, subplot_cols)
    end subroutine core_savefig_with_status

    subroutine core_show(state, plots, plot_count, blocking, annotations, &
                         annotation_count, &
                         subplots_array, subplot_rows, subplot_cols)
        type(figure_state_t), intent(inout) :: state
        type(plot_data_t), allocatable, intent(inout) :: plots(:)
        integer, intent(in) :: plot_count
        logical, intent(in), optional :: blocking
        type(text_annotation_t), allocatable, intent(inout) :: annotations(:)
        integer, intent(in) :: annotation_count
        type(subplot_data_t), intent(in), optional :: subplots_array(:, :)
        integer, intent(in), optional :: subplot_rows, subplot_cols

        call ensure_figure_storage(plots, state)
        call figure_show(state, plots, plot_count, blocking, annotations, &
                         annotation_count, &
                         subplots_array, subplot_rows, subplot_cols)
    end subroutine core_show

end module fortplot_figure_core_operations