Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions example/fortran/grid_demo.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
program grid_demo
!! Example demonstrating grid line capabilities
!! Shows basic grids, customization, and axis-specific grids

use, intrinsic :: iso_fortran_env, only: wp => real64
use fortplot
implicit none

type(figure_t) :: fig
real(wp) :: x(20), y1(20), y2(20)
integer :: i

! Create test data
do i = 1, 20
x(i) = real(i - 1, wp) * 0.5_wp
y1(i) = sin(x(i)) * exp(-x(i) * 0.1_wp)
y2(i) = cos(x(i)) * 0.8_wp
end do

! Basic plot with default grid (PNG)
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(.true.)
call fig%legend()
call fig%set_title('Basic Grid Lines')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_basic.png')
write(*,*) 'Created grid_basic.png'

! Basic plot with default grid (PDF)
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(.true.)
call fig%legend()
call fig%set_title('Basic Grid Lines')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_basic.pdf')
write(*,*) 'Created grid_basic.pdf'

! Grid with custom transparency
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(alpha=0.6_wp)
call fig%legend()
call fig%set_title('Grid with Custom Transparency (alpha=0.6)')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_custom_alpha.png')
write(*,*) 'Created grid_custom_alpha.png'

! Grid with custom line style
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(linestyle='--', alpha=0.4_wp)
call fig%legend()
call fig%set_title('Grid with Dashed Lines')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_dashed.png')
write(*,*) 'Created grid_dashed.png'

! X-axis grid only
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(axis='x')
call fig%legend()
call fig%set_title('X-Axis Grid Lines Only')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_x_only.png')
write(*,*) 'Created grid_x_only.png'

! Y-axis grid only
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(axis='y')
call fig%legend()
call fig%set_title('Y-Axis Grid Lines Only')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_y_only.png')
write(*,*) 'Created grid_y_only.png'

! Minor grid lines
call fig%initialize(800, 600)
call fig%add_plot(x, y1, label='Damped sine')
call fig%add_plot(x, y2, label='Cosine')
call fig%grid(which='minor', alpha=0.2_wp)
call fig%legend()
call fig%set_title('Minor Grid Lines')
call fig%set_xlabel('Time (s)')
call fig%set_ylabel('Amplitude')
call fig%savefig('plots/grid_minor.png')
write(*,*) 'Created grid_minor.png'

write(*,*) 'Grid lines demonstration completed!'

end program grid_demo
67 changes: 65 additions & 2 deletions src/fortplot_figure_core.f90
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ module fortplot_figure_core
! Line drawing properties
real(wp) :: current_line_width = 1.0_wp

! Grid line properties
logical :: grid_enabled = .false.
character(len=10) :: grid_axis = 'both'
character(len=10) :: grid_which = 'major'
real(wp) :: grid_alpha = 0.3_wp
character(len=10) :: grid_linestyle = '-'
real(wp), dimension(3) :: grid_color = [0.5_wp, 0.5_wp, 0.5_wp]

! Streamline data (temporary placeholder)
type(plot_data_t), allocatable :: streamlines(:)
logical :: has_error = .false.
Expand All @@ -126,6 +134,7 @@ module fortplot_figure_core
procedure :: set_xlim
procedure :: set_ylim
procedure :: set_line_width
procedure :: grid
procedure :: set_ydata
procedure :: legend => figure_legend
procedure :: show
Expand Down Expand Up @@ -466,6 +475,56 @@ subroutine set_line_width(self, width)
self%current_line_width = width
end subroutine set_line_width

subroutine grid(self, enable, axis, which, alpha, linestyle, color)
!! Enable/disable and customize grid lines
class(figure_t), intent(inout) :: self
logical, intent(in), optional :: enable
character(len=*), intent(in), optional :: axis, which, linestyle
real(wp), intent(in), optional :: alpha
real(wp), intent(in), optional :: color(3)

if (present(enable)) then
self%grid_enabled = enable
end if

if (present(axis)) then
if (axis == 'x' .or. axis == 'y' .or. axis == 'both') then
self%grid_axis = axis
self%grid_enabled = .true.
else
print *, 'Warning: Invalid axis value. Use "x", "y", or "both"'
end if
end if

if (present(which)) then
if (which == 'major' .or. which == 'minor') then
self%grid_which = which
self%grid_enabled = .true.
else
print *, 'Warning: Invalid which value. Use "major" or "minor"'
end if
end if

if (present(alpha)) then
if (alpha >= 0.0_wp .and. alpha <= 1.0_wp) then
self%grid_alpha = alpha
self%grid_enabled = .true.
else
print *, 'Warning: Alpha must be between 0.0 and 1.0'
end if
end if

if (present(linestyle)) then
self%grid_linestyle = linestyle
self%grid_enabled = .true.
end if

if (present(color)) then
self%grid_color = color
self%grid_enabled = .true.
end if
end subroutine grid

subroutine destroy(self)
!! Clean up figure resources
type(figure_t), intent(inout) :: self
Expand Down Expand Up @@ -926,11 +985,15 @@ subroutine render_figure_axes(self)
type is (png_context)
call draw_axes_and_labels(backend, self%xscale, self%yscale, self%symlog_threshold, &
self%x_min, self%x_max, self%y_min, self%y_max, &
self%title, self%xlabel, self%ylabel)
self%title, self%xlabel, self%ylabel, &
self%grid_enabled, self%grid_axis, self%grid_which, &
self%grid_alpha, self%grid_linestyle, self%grid_color)
type is (pdf_context)
call draw_pdf_axes_and_labels(backend, self%xscale, self%yscale, self%symlog_threshold, &
self%x_min, self%x_max, self%y_min, self%y_max, &
self%title, self%xlabel, self%ylabel)
self%title, self%xlabel, self%ylabel, &
self%grid_enabled, self%grid_axis, self%grid_which, &
self%grid_alpha, self%grid_linestyle, self%grid_color)
type is (ascii_context)
! ASCII backend: explicitly set title and draw simple axes
if (allocated(self%title)) then
Expand Down
80 changes: 79 additions & 1 deletion src/fortplot_pdf.f90
Original file line number Diff line number Diff line change
Expand Up @@ -821,14 +821,20 @@ end subroutine escape_pdf_string

subroutine draw_pdf_axes_and_labels(ctx, xscale, yscale, symlog_threshold, &
x_min_orig, x_max_orig, y_min_orig, y_max_orig, &
title, xlabel, ylabel)
title, xlabel, ylabel, &
grid_enabled, grid_axis, grid_which, &
grid_alpha, grid_linestyle, grid_color)
!! Draw plot axes and frame for PDF backend with scale-aware tick generation
!! Now matches PNG backend behavior with nice tick boundaries
type(pdf_context), intent(inout) :: ctx
character(len=*), intent(in), optional :: xscale, yscale
real(wp), intent(in), optional :: symlog_threshold
real(wp), intent(in), optional :: x_min_orig, x_max_orig, y_min_orig, y_max_orig
character(len=*), intent(in), optional :: title, xlabel, ylabel
logical, intent(in), optional :: grid_enabled
character(len=*), intent(in), optional :: grid_axis, grid_which, grid_linestyle
real(wp), intent(in), optional :: grid_alpha
real(wp), intent(in), optional :: grid_color(3)

real(wp) :: x_tick_values(20), y_tick_values(20)
real(wp) :: x_positions(20), y_positions(20)
Expand Down Expand Up @@ -922,7 +928,79 @@ subroutine draw_pdf_axes_and_labels(ctx, xscale, yscale, symlog_threshold, &

! Draw title and axis labels
call draw_pdf_title_and_labels(ctx, title, xlabel, ylabel)

! Draw grid lines if enabled
if (present(grid_enabled) .and. grid_enabled) then
call draw_pdf_grid_lines(ctx, x_positions, y_positions, num_x_ticks, num_y_ticks, &
grid_axis, grid_which, grid_alpha, grid_linestyle, grid_color)
end if
end subroutine draw_pdf_axes_and_labels

subroutine draw_pdf_grid_lines(ctx, x_positions, y_positions, num_x_ticks, num_y_ticks, &
grid_axis, grid_which, grid_alpha, grid_linestyle, grid_color)
!! Draw grid lines at tick positions for PDF backend
type(pdf_context), intent(inout) :: ctx
real(wp), intent(in) :: x_positions(:), y_positions(:)
integer, intent(in) :: num_x_ticks, num_y_ticks
character(len=*), intent(in), optional :: grid_axis, grid_which, grid_linestyle
real(wp), intent(in), optional :: grid_alpha
real(wp), intent(in), optional :: grid_color(3)

character(len=10) :: axis_choice, which_choice
real(wp) :: alpha_value, line_color(3)
integer :: i
real(wp) :: grid_y_top, grid_y_bottom, grid_x_left, grid_x_right
character(len=100) :: draw_cmd

! Set default values
axis_choice = 'both'
which_choice = 'major'
alpha_value = 0.3_wp
line_color = [0.5_wp, 0.5_wp, 0.5_wp]

if (present(grid_axis)) axis_choice = grid_axis
if (present(grid_which)) which_choice = grid_which
if (present(grid_alpha)) alpha_value = grid_alpha
if (present(grid_color)) line_color = grid_color

! Calculate plot area boundaries (PDF coordinates: Y=0 at bottom)
grid_y_bottom = real(ctx%height - ctx%plot_area%bottom - ctx%plot_area%height, wp)
grid_y_top = real(ctx%height - ctx%plot_area%bottom, wp)
grid_x_left = real(ctx%plot_area%left, wp)
grid_x_right = real(ctx%plot_area%left + ctx%plot_area%width, wp)

! Set grid line color with transparency
write(draw_cmd, '(F4.2, 1X, F4.2, 1X, F4.2, 1X, "RG")') line_color(1), line_color(2), line_color(3)
call ctx%stream_writer%add_to_stream(draw_cmd)

! Draw vertical grid lines (at x tick positions)
if (axis_choice == 'both' .or. axis_choice == 'x') then
do i = 1, num_x_ticks
! Convert from raster to PDF coordinates
write(draw_cmd, '(F8.2, 1X, F8.2, 1X, "m")') &
x_positions(i), grid_y_bottom
call ctx%stream_writer%add_to_stream(draw_cmd)
write(draw_cmd, '(F8.2, 1X, F8.2, 1X, "l")') &
x_positions(i), grid_y_top
call ctx%stream_writer%add_to_stream(draw_cmd)
call ctx%stream_writer%add_to_stream("S")
end do
end if

! Draw horizontal grid lines (at y tick positions)
if (axis_choice == 'both' .or. axis_choice == 'y') then
do i = 1, num_y_ticks
! Convert Y position to PDF coordinates
write(draw_cmd, '(F8.2, 1X, F8.2, 1X, "m")') &
grid_x_left, real(ctx%height, wp) - y_positions(i)
call ctx%stream_writer%add_to_stream(draw_cmd)
write(draw_cmd, '(F8.2, 1X, F8.2, 1X, "l")') &
grid_x_right, real(ctx%height, wp) - y_positions(i)
call ctx%stream_writer%add_to_stream(draw_cmd)
call ctx%stream_writer%add_to_stream("S")
end do
end if
end subroutine draw_pdf_grid_lines

subroutine draw_pdf_frame(ctx)
!! Draw the plot frame for PDF backend
Expand Down
Loading