fortplot_matplotlib_plot_wrappers.f90 Source File


Source Code

module fortplot_matplotlib_plot_wrappers
    !! Matplotlib-style plot creation wrappers built on top of fortplot figures

    use, intrinsic :: iso_fortran_env, only: wp => real64
    use fortplot_errorbar_plots, only: errorbar_impl => errorbar
    use fortplot_global, only: fig => global_figure
    use fortplot_logging, only: log_error
    use fortplot_matplotlib_session, only: ensure_fig_init
    use fortplot_plotting_advanced, only: bar_impl, barh_impl
    use fortplot_scatter_plots, only: add_scatter_2d, add_scatter_3d
    use fortplot_3d_plots, only: add_3d_plot_impl => add_3d_plot

    implicit none
    private

    public :: plot
    public :: scatter
    public :: errorbar
    public :: boxplot
    public :: bar
    public :: barh
    public :: hist
    public :: histogram
    public :: add_plot
    public :: add_errorbar
    public :: add_scatter
    public :: add_3d_plot

    interface add_scatter
        module procedure add_scatter_2d_wrapper
        module procedure add_scatter_3d_wrapper
    end interface add_scatter

contains

    subroutine plot(x, y, label, linestyle)
        real(wp), intent(in) :: x(:), y(:)
        character(len=*), intent(in), optional :: label, linestyle
        integer :: idx, nrows, ncols, row, col

        call ensure_fig_init()

        ! Route to subplot when a grid is active and a selection exists
        nrows = fig%subplot_rows
        ncols = fig%subplot_cols
        idx = fig%current_subplot

        if (nrows > 0 .and. ncols > 0 .and. idx >= 1 .and. idx <= nrows*ncols) then
            row = (idx - 1) / ncols + 1
            col = mod(idx - 1, ncols) + 1
            call fig%subplot_plot(row, col, x, y, label=label, linestyle=linestyle)
        else
            call fig%add_plot(x, y, label=label, linestyle=linestyle)
        end if
    end subroutine plot

    subroutine errorbar(x, y, xerr, yerr, fmt, label, capsize, linestyle, marker, &
                        color, elinewidth, capthick)
        real(wp), intent(in) :: x(:), y(:)
        real(wp), intent(in), optional :: xerr(:), yerr(:)
        character(len=*), intent(in), optional :: fmt, label, linestyle, marker
        real(wp), intent(in), optional :: capsize
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: elinewidth, capthick

        call ensure_fig_init()
        ! Route to the actual errorbar implementation so error bars are visible
        call errorbar_impl(fig, x, y, xerr=xerr, yerr=yerr, label=label, &
                           capsize=capsize, marker=marker, color=color, &
                           elinewidth=elinewidth, capthick=capthick)
    end subroutine errorbar

    subroutine bar(x, height, width, bottom, label, color, edgecolor, align)
        real(wp), intent(in) :: x(:), height(:)
        real(wp), intent(in), optional :: width
        real(wp), intent(in), optional :: bottom(:)
        character(len=*), intent(in), optional :: label, align
        real(wp), intent(in), optional :: color(3), edgecolor(3)

        real(wp) :: bar_width
        real(wp), allocatable :: bar_bottom(:)
        character(len=32) :: bar_align

        call ensure_fig_init()

        bar_width = 0.8_wp
        if (present(width)) bar_width = width

        allocate(bar_bottom(size(x)))
        bar_bottom = 0.0_wp
        if (present(bottom)) then
            if (size(bottom) == size(x)) then
                bar_bottom = bottom
            else if (size(bottom) == 1) then
                bar_bottom = bottom(1)
            else
                call log_error("bar: bottom array size must match x array or be scalar")
                deallocate(bar_bottom)
                return
            end if
        end if

        bar_align = 'center'
        if (present(align)) bar_align = align

        call bar_impl(fig, x, height, width=bar_width, label=label, color=color)
        deallocate(bar_bottom)
    end subroutine bar

    subroutine barh(y, width, height, left, label, color, edgecolor, align)
        real(wp), intent(in) :: y(:), width(:)
        real(wp), intent(in), optional :: height
        real(wp), intent(in), optional :: left(:)
        character(len=*), intent(in), optional :: label, align
        real(wp), intent(in), optional :: color(3), edgecolor(3)

        real(wp) :: bar_height
        real(wp), allocatable :: bar_left(:)
        character(len=32) :: bar_align

        call ensure_fig_init()

        bar_height = 0.8_wp
        if (present(height)) bar_height = height

        allocate(bar_left(size(y)))
        bar_left = 0.0_wp
        if (present(left)) then
            if (size(left) == size(y)) then
                bar_left = left
            else if (size(left) == 1) then
                bar_left = left(1)
            else
                call log_error("barh: left array size must match y array or be scalar")
                deallocate(bar_left)
                return
            end if
        end if

        bar_align = 'center'
        if (present(align)) bar_align = align

        call barh_impl(fig, y, width, height=bar_height, label=label, color=color)
        deallocate(bar_left)
    end subroutine barh

    subroutine hist(data, bins, density, label, color)
        real(wp), intent(in) :: data(:)
        integer, intent(in), optional :: bins
        logical, intent(in), optional :: density
        character(len=*), intent(in), optional :: label
        real(wp), intent(in), optional :: color(3)

        call ensure_fig_init()
        call fig%add_hist(data, bins=bins, density=density, label=label, &
                          color=color)
    end subroutine hist

    subroutine histogram(data, bins, density, label, color)
        real(wp), intent(in) :: data(:)
        integer, intent(in), optional :: bins
        logical, intent(in), optional :: density
        character(len=*), intent(in), optional :: label
        real(wp), intent(in), optional :: color(3)

        call hist(data, bins=bins, density=density, label=label, color=color)
    end subroutine histogram

    subroutine boxplot(data, position, width, label, show_outliers, horizontal, color)
        real(wp), intent(in) :: data(:)
        real(wp), intent(in), optional :: position
        real(wp), intent(in), optional :: width
        character(len=*), intent(in), optional :: label
        logical, intent(in), optional :: show_outliers, horizontal
        character(len=*), intent(in), optional :: color

        call ensure_fig_init()
        call fig%boxplot(data, position=position, width=width, label=label, &
                         show_outliers=show_outliers, horizontal=horizontal, &
                         color=color)
    end subroutine boxplot

    subroutine scatter(x, y, s, c, label, marker, markersize, color, &
                          linewidths, edgecolors, alpha)
        real(wp), intent(in) :: x(:), y(:)
        real(wp), intent(in), optional :: s
        real(wp), intent(in), optional :: c(:)
        character(len=*), intent(in), optional :: label, marker
        real(wp), intent(in), optional :: markersize
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: linewidths
        real(wp), intent(in), optional :: edgecolors(3)
        real(wp), intent(in), optional :: alpha

        call scatter_2d_entry(x, y, label=label, marker=marker)
    end subroutine scatter

    subroutine add_scatter_2d_wrapper(x, y, s, c, label, marker, markersize, &
                                          color, linewidths, edgecolors, alpha)
        real(wp), intent(in) :: x(:), y(:)
        real(wp), intent(in), optional :: s
        real(wp), intent(in), optional :: c(:)
        character(len=*), intent(in), optional :: label, marker
        real(wp), intent(in), optional :: markersize
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: linewidths
        real(wp), intent(in), optional :: edgecolors(3)
        real(wp), intent(in), optional :: alpha

        call scatter_2d_entry(x, y, label=label, marker=marker)
    end subroutine add_scatter_2d_wrapper

    subroutine add_scatter_3d_wrapper(x, y, z, s, c, label, marker, markersize, &
                                          color, linewidths, edgecolors, alpha)
        real(wp), intent(in) :: x(:), y(:), z(:)
        real(wp), intent(in), optional :: s
        real(wp), intent(in), optional :: c(:)
        character(len=*), intent(in), optional :: label, marker
        real(wp), intent(in), optional :: markersize
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: linewidths
        real(wp), intent(in), optional :: edgecolors(3)
        real(wp), intent(in), optional :: alpha

        real(wp), allocatable :: wx(:), wy(:), wz(:)

        call ensure_fig_init()
        allocate(wx(size(x)), wy(size(y)), wz(size(z)))
        wx = x
        wy = y
        wz = z
        call add_scatter_3d(fig, wx, wy, wz, label=label, marker=marker)
        deallocate(wx, wy, wz)
    end subroutine add_scatter_3d_wrapper

    subroutine add_plot(x, y, label, linestyle)
        real(wp), intent(in) :: x(:), y(:)
        character(len=*), intent(in), optional :: label, linestyle

        call ensure_fig_init()
        call fig%add_plot(x, y, label=label, linestyle=linestyle)
    end subroutine add_plot

    subroutine add_errorbar(x, y, xerr, yerr, fmt, label, capsize, linestyle, &
                               marker, color, elinewidth, capthick)
        real(wp), intent(in) :: x(:), y(:)
        real(wp), intent(in), optional :: xerr(:), yerr(:)
        character(len=*), intent(in), optional :: fmt, label, linestyle, marker
        real(wp), intent(in), optional :: capsize
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: elinewidth, capthick

        call ensure_fig_init()
        call errorbar_impl(fig, x, y, xerr=xerr, yerr=yerr, label=label, &
                           capsize=capsize, marker=marker, color=color, &
                           elinewidth=elinewidth, capthick=capthick)
    end subroutine add_errorbar

    subroutine add_3d_plot(x, y, z, label, linestyle, color, linewidth, marker, &
                              markersize)
        real(wp), intent(in) :: x(:), y(:), z(:)
        character(len=*), intent(in), optional :: label, linestyle, marker
        real(wp), intent(in), optional :: color(3)
        real(wp), intent(in), optional :: linewidth, markersize

        call ensure_fig_init()
        call add_3d_plot_impl(fig, x, y, z, label=label, linestyle=linestyle, &
                              marker=marker, markersize=markersize, linewidth=linewidth)
    end subroutine add_3d_plot

    subroutine scatter_2d_entry(x, y, label, marker)
        real(wp), intent(in) :: x(:), y(:)
        character(len=*), intent(in), optional :: label, marker

        real(wp), allocatable :: wx(:), wy(:)

        call ensure_fig_init()
        allocate(wx(size(x)), wy(size(y)))
        wx = x
        wy = y
        call add_scatter_2d(fig, wx, wy, label=label, marker=marker)
        deallocate(wx, wy)
    end subroutine scatter_2d_entry

end module fortplot_matplotlib_plot_wrappers