module fortplot_matplotlib_mesh_wrappers !! Pcolormesh and surface visualisation wrappers for matplotlib facade use, intrinsic :: iso_fortran_env, only: wp => real64 use fortplot_global, only: fig => global_figure use fortplot_figure_core, only: figure_t use fortplot_figure_initialization, only: ensure_figure_storage use fortplot_figure_grid_plot_registration, only: & add_parametric_surface_plot_data use fortplot_logging, only: log_error, log_warning use fortplot_matplotlib_color_utils, only: resolve_color_string_or_rgb use fortplot_matplotlib_session, only: ensure_fig_init contains subroutine add_parametric_surface(x, y, z, color, linewidth, label, & row_stride, column_stride, cmap, & show_colorbar, alpha, edgecolor, filled, & colormap) !! Draw a tensor-product parametric surface as a wireframe or shaded mesh. !! !! Unlike ``add_surface``, which accepts a height field ``z(y,x)``, !! this helper accepts physical coordinates for every grid point. It !! is therefore suitable for closed curved surfaces such as spheres, !! toroids, and trimmed spline patches. ``filled=.true.`` emits shaded !! quadrilateral facets with painter depth ordering; the default remains !! the historical wireframe representation. real(wp), contiguous, intent(in) :: x(:, :), y(:, :), z(:, :) character(len=*), intent(in), optional :: color, label, cmap, colormap logical, intent(in), optional :: show_colorbar, filled real(wp), intent(in), optional :: alpha, edgecolor(3) real(wp), intent(in), optional :: linewidth integer, intent(in), optional :: row_stride, column_stride real(wp) :: color_rgb(3) logical :: has_color character(len=:), allocatable :: cmap_local if (size(x, 1) < 2 .or. size(x, 2) < 2 .or. & any(shape(y) /= shape(x)) .or. any(shape(z) /= shape(x))) then call log_error("add_parametric_surface: x, y, and z must have " // & "identical shapes of at least 2 by 2") return end if call ensure_fig_init() call ensure_figure_storage(fig%plots, fig%state) call resolve_color_string_or_rgb(color_str=color, color_rgb=edgecolor, & context='add_parametric_surface', & rgb_out=color_rgb, has_color=has_color) if (present(cmap)) then cmap_local = cmap else if (present(colormap)) then cmap_local = colormap end if if (allocated(cmap_local)) then if (has_color) then call add_parametric_surface_plot_data( & fig%plots, fig%state%plot_count, fig%state%max_plots, & fig%state%colors, x, y, z, label=label, cmap=cmap_local, & show_colorbar=show_colorbar, alpha=alpha, edgecolor=color_rgb, & linewidth=linewidth, filled=filled, row_stride=row_stride, & column_stride=column_stride) else call add_parametric_surface_plot_data( & fig%plots, fig%state%plot_count, fig%state%max_plots, & fig%state%colors, x, y, z, label=label, cmap=cmap_local, & show_colorbar=show_colorbar, alpha=alpha, linewidth=linewidth, & filled=filled, row_stride=row_stride, column_stride=column_stride) end if else if (has_color) then call add_parametric_surface_plot_data( & fig%plots, fig%state%plot_count, fig%state%max_plots, & fig%state%colors, x, y, z, label=label, show_colorbar=show_colorbar, & alpha=alpha, edgecolor=color_rgb, linewidth=linewidth, filled=filled, & row_stride=row_stride, column_stride=column_stride) else call add_parametric_surface_plot_data( & fig%plots, fig%state%plot_count, fig%state%max_plots, & fig%state%colors, x, y, z, label=label, show_colorbar=show_colorbar, & alpha=alpha, linewidth=linewidth, filled=filled, row_stride=row_stride, & column_stride=column_stride) end if if (fig%state%plot_count > 0) then fig%plots(fig%state%plot_count)%axis = fig%state%active_axis end if fig%plot_count = fig%state%plot_count end subroutine add_parametric_surface subroutine pcolormesh(x, y, z, shading, cmap, show_colorbar, label, & edgecolors, linewidths, vmin, vmax, colormap) !! Draw a pseudocolor mesh (matplotlib-compatible) !! !! Parameters !! x : real(wp), contiguous, intent(in) !! X grid coordinates. !! y : real(wp), contiguous, intent(in) !! Y grid coordinates. !! z : real(wp), contiguous, intent(in) !! Cell or node values on the grid. !! shading : character(len=*), optional !! Matplotlib shading keyword. !! cmap : character(len=*), optional !! Colormap name. !! show_colorbar : logical, optional !! Accepted for matplotlib parity. !! label : character(len=*), optional !! Legend label. !! edgecolors : real(wp)(3), optional !! Accepted for matplotlib parity. !! linewidths : real(wp), optional !! Mesh line width. !! vmin : real(wp), optional !! Lower color limit. !! vmax : real(wp), optional !! Upper color limit. !! colormap : character(len=*), optional !! Deprecated alias for cmap. real(wp), contiguous, intent(in) :: x(:), y(:) real(wp), contiguous, intent(in) :: z(:,:) character(len=*), intent(in), optional :: shading, cmap, label, colormap logical, intent(in), optional :: show_colorbar real(wp), intent(in), optional :: edgecolors(3) real(wp), intent(in), optional :: linewidths real(wp), intent(in), optional :: vmin, vmax character(len=32) :: shading_local, colormap_local, label_local character(len=:), allocatable :: resolved_cmap logical :: show_colorbar_local real(wp) :: vmin_local, vmax_local, linewidths_local integer :: nx, ny call ensure_fig_init() nx = size(x) ny = size(y) ! Matplotlib flat shading: z(ny-1, nx-1); nearest/gouraud: z(ny, nx). ! Transposed shapes are rejected to prevent silent masking of user errors. if (.not. (size(z, 1) == ny - 1 .and. size(z, 2) == nx - 1) .and. & .not. (size(z, 1) == ny .and. size(z, 2) == nx)) then call log_error( & "pcolormesh: z dimensions incompatible with x,y grid. " // & "Expected z(ny-1,nx-1) for flat shading or z(ny,nx) for nearest/gouraud.") return end if shading_local = 'flat' if (present(shading)) shading_local = shading call resolve_cmap_alias(cmap, colormap, resolved_cmap) colormap_local = 'viridis' if (allocated(resolved_cmap)) colormap_local = resolved_cmap show_colorbar_local = .false. if (present(show_colorbar)) show_colorbar_local = show_colorbar label_local = '' if (present(label)) label_local = label linewidths_local = 1.0_wp if (present(linewidths)) linewidths_local = linewidths if (present(vmin)) then vmin_local = vmin else vmin_local = minval(z) end if if (present(vmax)) then vmax_local = vmax else vmax_local = maxval(z) end if call fig%add_pcolormesh(x, y, z, shading=shading_local, & cmap=colormap_local, vmin=vmin_local, & vmax=vmax_local, linewidths=linewidths_local) end subroutine pcolormesh subroutine add_pcolormesh(x, y, z, shading, cmap, show_colorbar, label, & edgecolors, linewidths, vmin, vmax, colormap) !! Object-oriented pcolormesh helper. !! !! Parameters !! x : real(wp), contiguous, intent(in) !! X grid coordinates. !! y : real(wp), contiguous, intent(in) !! Y grid coordinates. !! z : real(wp), contiguous, intent(in) !! Cell or node values on the grid. !! shading : character(len=*), optional !! Matplotlib shading keyword. !! cmap : character(len=*), optional !! Colormap name. !! show_colorbar : logical, optional !! Accepted for matplotlib parity. !! label : character(len=*), optional !! Legend label. !! edgecolors : real(wp)(3), optional !! Accepted for matplotlib parity. !! linewidths : real(wp), optional !! Mesh line width. !! vmin : real(wp), optional !! Lower color limit. !! vmax : real(wp), optional !! Upper color limit. !! colormap : character(len=*), optional !! Deprecated alias for cmap. real(wp), contiguous, intent(in) :: x(:), y(:) real(wp), contiguous, intent(in) :: z(:,:) character(len=*), intent(in), optional :: shading, cmap, label, colormap logical, intent(in), optional :: show_colorbar real(wp), intent(in), optional :: edgecolors(3) real(wp), intent(in), optional :: linewidths real(wp), intent(in), optional :: vmin, vmax call pcolormesh(x, y, z, shading=shading, cmap=cmap, & show_colorbar=show_colorbar, label=label, & edgecolors=edgecolors, linewidths=linewidths, vmin=vmin, & vmax=vmax, colormap=colormap) end subroutine add_pcolormesh subroutine add_surface(x, y, z, cmap, show_colorbar, alpha, edgecolor, & linewidth, label, filled, colormap) !! Object-oriented surface helper. !! !! Parameters !! x : real(wp), contiguous, intent(in) !! X grid coordinates. !! y : real(wp), contiguous, intent(in) !! Y grid coordinates. !! z : real(wp), contiguous, intent(in) !! Surface values on the grid. !! cmap : character(len=*), optional !! Colormap name. !! show_colorbar : logical, optional !! Accepted for matplotlib parity. !! alpha : real(wp), optional !! Surface transparency. !! edgecolor : real(wp)(3), optional !! Surface edge color. !! linewidth : real(wp), optional !! Surface line width. !! label : character(len=*), optional !! Legend label. !! filled : logical, optional !! Accepted for matplotlib parity. !! colormap : character(len=*), optional !! Deprecated alias for cmap. real(wp), contiguous, intent(in) :: x(:), y(:) real(wp), contiguous, intent(in) :: z(:,:) character(len=*), intent(in), optional :: cmap, label, colormap logical, intent(in), optional :: show_colorbar, filled real(wp), intent(in), optional :: alpha, linewidth real(wp), intent(in), optional :: edgecolor(3) integer :: nx, ny character(len=:), allocatable :: resolved_cmap call ensure_fig_init() nx = size(x) ny = size(y) ! Matplotlib surface: z(ny, nx) with x(nx), y(ny). ! Transposed shapes are rejected to prevent silent masking of user errors. if (.not. (size(z, 1) == ny .and. size(z, 2) == nx)) then call log_error( & "add_surface: z dimensions incompatible with x,y grid. " // & "Expected z(ny,nx) where x has nx points and y has ny points.") return end if call resolve_cmap_alias(cmap, colormap, resolved_cmap) call fig%add_surface(x, y, z, label=label, cmap=resolved_cmap, & show_colorbar=show_colorbar, alpha=alpha, & edgecolor=edgecolor, linewidth=linewidth, & filled=filled, colormap=resolved_cmap) end subroutine add_surface subroutine resolve_cmap_alias(cmap, colormap, resolved) !! Resolve matplotlib-canonical cmap against legacy colormap alias character(len=*), intent(in), optional :: cmap, colormap character(len=:), allocatable, intent(out) :: resolved if (present(cmap)) then resolved = cmap else if (present(colormap)) then call log_warning( & "field wrappers: 'colormap' is deprecated; use 'cmap' for parity") resolved = colormap end if end subroutine resolve_cmap_alias end module fortplot_matplotlib_mesh_wrappers