submodule(fortplot_figure_core) fortplot_figure_core_fill_between implicit none contains module subroutine add_fill_between(self, x, y1, y2, where, color, alpha, & interpolate) class(figure_t), intent(inout) :: self real(wp), contiguous, intent(in) :: x(:), y1(:) real(wp), intent(in), optional :: y2(:) logical, intent(in), optional :: where (:) character(len=*), intent(in), optional :: color real(wp), intent(in), optional :: alpha logical, intent(in), optional :: interpolate integer :: n real(wp), allocatable :: upper_vals(:), lower_vals(:) logical, allocatable :: mask_vals(:) logical :: has_mask n = size(x) if (.not. prepare_fill_between_values(n, y1, y2, where, upper_vals, & lower_vals, mask_vals, has_mask)) then call cleanup_fill_between_values(upper_vals, lower_vals, mask_vals) return end if if (present(interpolate)) then call log_warning('fill_between: interpolate option ignored') end if if (has_mask) then call add_prepared_fill_between(self, x, upper_vals, lower_vals, & mask=mask_vals, color=color, alpha=alpha) else call add_prepared_fill_between(self, x, upper_vals, lower_vals, & color=color, alpha=alpha) end if self%plot_count = self%state%plot_count end subroutine add_fill_between subroutine cleanup_fill_between_values(upper_vals, lower_vals, mask_vals) real(wp), allocatable, intent(inout) :: upper_vals(:), lower_vals(:) logical, allocatable, intent(inout) :: mask_vals(:) if (allocated(upper_vals)) deallocate (upper_vals) if (allocated(lower_vals)) deallocate (lower_vals) if (allocated(mask_vals)) deallocate (mask_vals) end subroutine cleanup_fill_between_values logical function prepare_fill_between_values(n, y1, y2, where, upper_vals, & lower_vals, mask_vals, has_mask) & result(ok) integer, intent(in) :: n real(wp), contiguous, intent(in) :: y1(:) real(wp), intent(in), optional :: y2(:) logical, intent(in), optional :: where(:) real(wp), allocatable, intent(out) :: upper_vals(:), lower_vals(:) logical, allocatable, intent(out) :: mask_vals(:) logical, intent(out) :: has_mask ok = .false. has_mask = .false. if (n < 2) then call log_error('fill_between: need at least two points to form area') return end if if (size(y1) /= n) then call log_error('fill_between: y1 size mismatch') return end if allocate (upper_vals(n), lower_vals(n)) upper_vals = y1 if (.not. assign_fill_between_bound(n, y2, lower_vals, 'y2')) return if (.not. assign_fill_between_mask(n, where, mask_vals, has_mask)) return ok = .true. end function prepare_fill_between_values logical function assign_fill_between_bound(n, source, target, name) result(ok) integer, intent(in) :: n real(wp), intent(in), optional :: source(:) real(wp), intent(out) :: target(:) character(len=*), intent(in) :: name ok = .false. if (present(source)) then if (size(source) /= n) then call log_error('fill_between: '//name//' size mismatch') return end if target = source else target = 0.0_wp end if ok = .true. end function assign_fill_between_bound logical function assign_fill_between_mask(n, where, mask_vals, has_mask) & result(ok) integer, intent(in) :: n logical, intent(in), optional :: where(:) logical, allocatable, intent(out) :: mask_vals(:) logical, intent(out) :: has_mask ok = .false. has_mask = .false. if (.not. present(where)) then ok = .true. return end if if (size(where) /= n) then call log_error('fill_between: where mask size mismatch') return end if allocate (mask_vals(n)) mask_vals = where if (.not. any(mask_vals)) then call log_warning('fill_between: mask excludes all data points') return end if has_mask = .true. ok = .true. end function assign_fill_between_mask subroutine add_prepared_fill_between(self, x, upper_vals, lower_vals, mask, & color, alpha) class(figure_t), intent(inout) :: self real(wp), contiguous, intent(in) :: x(:), upper_vals(:), lower_vals(:) logical, intent(in), optional :: mask(:) character(len=*), intent(in), optional :: color real(wp), intent(in), optional :: alpha integer :: row, col type(figure_state_t) :: panel_state if (self%subplot_rows > 0 .and. self%subplot_cols > 0) then row = (self%current_subplot - 1)/self%subplot_cols + 1 col = mod(self%current_subplot - 1, self%subplot_cols) + 1 associate (panel => self%subplots_array(row, col)) panel_state%colors = self%state%colors panel_state%plot_count = panel%plot_count panel_state%max_plots = panel%max_plots call core_add_fill_between(panel%plots, panel_state, x, upper_vals, & lower_vals, mask=mask, color_string=color, alpha=alpha, & plot_count=panel%plot_count) end associate self%state%rendered = .false. return end if call core_add_fill_between(self%plots, self%state, x, upper_vals, & lower_vals, mask=mask, color_string=color, alpha=alpha, & plot_count=self%plot_count) end subroutine add_prepared_fill_between end submodule fortplot_figure_core_fill_between