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
81 changes: 81 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
cmake_minimum_required(VERSION 3.20)
project(fortplot VERSION 2025.08.17 LANGUAGES Fortran C)

# Set build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

# Compiler options
set(CMAKE_Fortran_FLAGS "-Wall -Wextra -fimplicit-none")
set(CMAKE_Fortran_FLAGS_DEBUG "-g -O0 -fcheck=all")
set(CMAKE_Fortran_FLAGS_RELEASE "-O3")

# Set position independent code for shared library support
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Find all source files automatically
file(GLOB_RECURSE FORTRAN_SOURCES "src/*.f90")
file(GLOB_RECURSE C_SOURCES "src/*.c")

# Debug output
list(LENGTH FORTRAN_SOURCES fortran_count)
list(LENGTH C_SOURCES c_count)
message(STATUS "Found ${fortran_count} Fortran source files")
message(STATUS "Found ${c_count} C source files")

# Create the fortplot library
add_library(fortplot ${FORTRAN_SOURCES} ${C_SOURCES})

# Set Fortran module directory
set_target_properties(fortplot PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/modules
)

# Include module directory for dependent projects
target_include_directories(fortplot
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/modules>
$<INSTALL_INTERFACE:include>
)

# Create namespaced alias for use in parent projects
add_library(fortplot::fortplot ALIAS fortplot)

# Export configuration for find_package() support
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
# This is a subproject - don't install
message(STATUS "fortplot configured as subproject")
else()
# This is the main project - configure install
include(GNUInstallDirs)

install(TARGETS fortplot
EXPORT fortplotTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/modules/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.mod"
)

install(EXPORT fortplotTargets
FILE fortplotTargets.cmake
NAMESPACE fortplot::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fortplot
)

include(CMakePackageConfigHelpers)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/fortplotConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/fortplotConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fortplot
)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fortplotConfig.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fortplot
)
endif()
23 changes: 15 additions & 8 deletions src/fortplot.f90
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ module fortplot
use fortplot_figure, only: figure_t
use fortplot_format_parser, only: parse_format_string, contains_format_chars
use fortplot_animation, only: animation_t, FuncAnimation
use fortplot_logging, only: set_log_level, log_error, log_warning, log_info, &
LOG_LEVEL_SILENT, LOG_LEVEL_ERROR, &
LOG_LEVEL_WARNING, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG

implicit none

Expand All @@ -37,6 +40,10 @@ module fortplot

! Animation interface
public :: animation_t, FuncAnimation

! Logging interface
public :: set_log_level, LOG_LEVEL_SILENT, LOG_LEVEL_ERROR, &
LOG_LEVEL_WARNING, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG

! Line style constants (pyplot-style)
character(len=*), parameter, public :: LINESTYLE_SOLID = '-'
Expand Down Expand Up @@ -225,7 +232,7 @@ subroutine hist(data, bins, density, label, color)
call ensure_global_figure_initialized()
! TODO: Implement hist method in figure_core
! call fig%hist(data, bins=bins, density=density, label=label, color=color)
print *, "ERROR: hist() not yet implemented - please use main branch for histogram support"
call log_error("hist() not yet implemented - please use main branch for histogram support")
end subroutine hist

subroutine histogram(data, bins, density, label, color)
Expand Down Expand Up @@ -253,7 +260,7 @@ subroutine histogram(data, bins, density, label, color)
call ensure_global_figure_initialized()
! TODO: Implement hist method in figure_core
! call fig%hist(data, bins=bins, density=density, label=label, color=color)
print *, "ERROR: hist() not yet implemented - please use main branch for histogram support"
call log_error("hist() not yet implemented - please use main branch for histogram support")
end subroutine histogram

subroutine boxplot(data, position, width, label, show_outliers, horizontal, color)
Expand Down Expand Up @@ -285,7 +292,7 @@ subroutine boxplot(data, position, width, label, show_outliers, horizontal, colo
! TODO: Implement boxplot method in figure_core
! call fig%boxplot(data, position=position, width=width, label=label, &
! show_outliers=show_outliers, horizontal=horizontal, color=color)
print *, "ERROR: boxplot() not yet implemented - please use main branch for boxplot support"
call log_error("boxplot() not yet implemented - please use main branch for boxplot support")
end subroutine boxplot

subroutine show_data(x, y, label, title_text, xlabel_text, ylabel_text, blocking)
Expand Down Expand Up @@ -666,13 +673,13 @@ subroutine show_viewer_implementation(blocking)
call execute_command_line(command, wait=.false., exitstat=stat)

if (stat /= 0) then
print *, 'Warning: Failed to open plot viewer. Plot saved to: ', trim(temp_filename)
print *, 'Please open the file manually with your preferred PDF viewer.'
call log_warning('Failed to open plot viewer. Plot saved to: ' // trim(temp_filename))
call log_info('Please open the file manually with your preferred PDF viewer.')
else
print *, 'Plot opened in default viewer. File: ', trim(temp_filename)
call log_info('Plot opened in default viewer. File: ' // trim(temp_filename))

if (do_block) then
print *, 'Press Enter to continue and clean up temporary file...'
call log_info('Press Enter to continue and clean up temporary file...')
read(*,*)

! Clean up temporary file
Expand All @@ -688,7 +695,7 @@ subroutine show_viewer_implementation(blocking)
call execute_command_line(command)
else
! In non-blocking mode, just inform that file stays
print *, 'Note: Temporary file will remain at: ', trim(temp_filename)
call log_info('Note: Temporary file will remain at: ' // trim(temp_filename))
end if
end if
end subroutine show_viewer_implementation
Expand Down
21 changes: 11 additions & 10 deletions src/fortplot_animation.f90
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module fortplot_animation
use fortplot_pipe, only: open_ffmpeg_pipe, write_png_to_pipe, close_ffmpeg_pipe
use fortplot_png, only: png_context, create_png_canvas, get_png_data
use fortplot_mpeg1_format, only: encode_animation_to_mpeg1
use fortplot_logging, only: log_error, log_info, log_warning
implicit none
private

Expand Down Expand Up @@ -63,11 +64,11 @@ subroutine run(self)
integer :: i

if (.not. associated(self%animate_func)) then
print *, "Error: Animation callback function not associated"
call log_error("Animation callback function not associated")
return
end if

print *, "Running animation with", self%frames, "frames..."
call log_info("Running animation with frames...")

do i = 1, self%frames
call self%animate_func(i)
Expand All @@ -78,7 +79,7 @@ subroutine run(self)
end if
end do

print *, "Animation completed."
call log_info("Animation completed.")
end subroutine run

subroutine set_save_frames(self, pattern)
Expand Down Expand Up @@ -119,13 +120,13 @@ subroutine save(self, filename, fps, status)

if (.not. is_video_format(extension)) then
if (present(status)) status = -3
print *, "Error: Unsupported file format. Use .mp4, .avi, or .mkv"
call log_error("Unsupported file format. Use .mp4, .avi, or .mkv")
return
end if

if (.not. check_ffmpeg_available()) then
if (present(status)) status = -1
print *, "Error: ffmpeg not found. Please install ffmpeg to save animations."
call log_error("ffmpeg not found. Please install ffmpeg to save animations.")
return
end if

Expand Down Expand Up @@ -230,7 +231,7 @@ subroutine save_animation_with_ffmpeg_pipe(anim, filename, fps, status)
if (should_use_native_encoder(anim, filename)) then
call save_animation_with_native_mpeg1(anim, filename, fps, status)
if (status == 0) return ! Native encoder succeeded
print *, "Native MPEG-1 encoder failed, falling back to FFmpeg"
call log_warning("Native MPEG-1 encoder failed, falling back to FFmpeg")
end if

! Fall back to FFmpeg pipeline
Expand Down Expand Up @@ -327,23 +328,23 @@ subroutine save_animation_with_ffmpeg_pipeline(anim, filename, fps, status)
stat = open_ffmpeg_pipe(filename, fps)
if (stat /= 0) then
status = -4
print *, "Error: Could not open pipe to ffmpeg"
call log_error("Could not open pipe to ffmpeg")
return
end if

do frame_idx = 1, anim%frames
call generate_png_frame_data(anim, frame_idx, png_data, stat)
if (stat /= 0) then
status = -5
print *, "Error: Failed to generate frame", frame_idx
call log_error("Failed to generate frame")
stat = close_ffmpeg_pipe()
return
end if

stat = write_png_to_pipe(png_data)
if (stat /= 0) then
status = -6
print *, "Error: Failed to write frame to pipe", frame_idx
call log_error("Failed to write frame to pipe")
stat = close_ffmpeg_pipe()
return
end if
Expand All @@ -358,7 +359,7 @@ subroutine save_animation_with_ffmpeg_pipeline(anim, filename, fps, status)
status = 0
else
status = -7
print *, "Error: Generated video failed validation"
call log_error("Generated video failed validation")
end if
end subroutine save_animation_with_ffmpeg_pipeline

Expand Down
3 changes: 2 additions & 1 deletion src/fortplot_ascii.f90
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module fortplot_ascii
!! Author: fortplot contributors

use fortplot_context
use fortplot_logging, only: log_info
use fortplot_latex_parser
use fortplot_unicode
use, intrinsic :: iso_fortran_env, only: wp => real64
Expand Down Expand Up @@ -251,7 +252,7 @@ subroutine ascii_finalize(this, filename)
open(newunit=unit, file=filename, status='replace')
call output_to_file(this, unit)
close(unit)
print *, "Unicode plot saved to '", trim(filename), "'"
call log_info("Unicode plot saved to '" // trim(filename) // "'")
end if
end subroutine ascii_finalize

Expand Down
21 changes: 11 additions & 10 deletions src/fortplot_figure_core.f90
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module fortplot_figure_core
use fortplot_scales
use fortplot_utils
use fortplot_axes
use fortplot_logging, only: log_warning, log_info
use fortplot_gltf, only: gltf_context
use fortplot_colormap
use fortplot_pcolormesh
Expand All @@ -27,7 +28,8 @@ module fortplot_figure_core

private
public :: figure_t, plot_data_t, subplot_t
public :: PLOT_TYPE_LINE, PLOT_TYPE_CONTOUR, PLOT_TYPE_PCOLORMESH, PLOT_TYPE_ERRORBAR, PLOT_TYPE_BAR, PLOT_TYPE_HISTOGRAM, PLOT_TYPE_BOXPLOT
public :: PLOT_TYPE_LINE, PLOT_TYPE_CONTOUR, PLOT_TYPE_PCOLORMESH, &
PLOT_TYPE_ERRORBAR, PLOT_TYPE_BAR, PLOT_TYPE_HISTOGRAM, PLOT_TYPE_BOXPLOT

integer, parameter :: PLOT_TYPE_LINE = 1
integer, parameter :: PLOT_TYPE_CONTOUR = 2
Expand Down Expand Up @@ -630,11 +632,11 @@ subroutine savefig(self, filename, blocking)
call self%backend%save(filename)
end select

write(*, '(A, A, A)') 'Saved figure: ', trim(filename)
call log_info('Saved figure: ' // trim(filename))

! If blocking requested, wait for user input
if (do_block) then
print *, "Press Enter to continue..."
call log_info("Press Enter to continue...")
read(*,*)
end if
end subroutine savefig
Expand Down Expand Up @@ -663,7 +665,7 @@ subroutine show(self, blocking)

! If blocking requested, wait for user input
if (do_block) then
print *, "Press Enter to continue..."
call log_info("Press Enter to continue...")
read(*,*)
end if
end subroutine show
Expand Down Expand Up @@ -2536,23 +2538,22 @@ subroutine set_ydata(self, plot_index, y_new)
real(wp), intent(in) :: y_new(:)

if (plot_index < 1 .or. plot_index > self%plot_count) then
print *, "Warning: Invalid plot index", plot_index, "for set_ydata"
call log_warning("Invalid plot index for set_ydata")
return
end if

if (self%plots(plot_index)%plot_type /= PLOT_TYPE_LINE) then
print *, "Warning: set_ydata only supported for line plots"
call log_warning("set_ydata only supported for line plots")
return
end if

if (.not. allocated(self%plots(plot_index)%y)) then
print *, "Warning: Plot", plot_index, "has no y data to update"
call log_warning("Plot has no y data to update")
return
end if

if (size(y_new) /= size(self%plots(plot_index)%y)) then
print *, "Warning: New y data size", size(y_new), &
"does not match existing size", size(self%plots(plot_index)%y)
call log_warning("New y data size does not match existing size")
return
end if

Expand Down Expand Up @@ -2634,7 +2635,7 @@ subroutine ensure_directory_exists(filename)
write(command, '(A,A,A)') 'mkdir -p "', trim(dir_path), '"'
call execute_command_line(command, exitstat=status)
if (status /= 0) then
print *, "Warning: Could not create directory: ", trim(dir_path)
call log_warning("Could not create directory: " // trim(dir_path))
end if
end if
end subroutine ensure_directory_exists
Expand Down
9 changes: 5 additions & 4 deletions src/fortplot_gltf.f90
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module fortplot_gltf
use fortplot_context, only: plot_context, setup_canvas
use fortplot_gltf_base
use fortplot_gltf_writer
use fortplot_logging, only: log_info, log_error
use fortplot_gltf_geometry
use fortplot_gltf_buffer
use fortplot_glb_writer
Expand Down Expand Up @@ -76,9 +77,9 @@ subroutine save_gltf(this, filename)
! Write GLB binary format
if (allocated(this%buffer_data)) then
call write_glb_file(filename, json, this%buffer_data)
print *, "GLB file '" // trim(filename) // "' created successfully!"
call log_info("GLB file '" // trim(filename) // "' created successfully!")
else
print *, "Error: No binary data for GLB file"
call log_error("No binary data for GLB file")
end if
else
! Write GLTF text format
Expand All @@ -87,9 +88,9 @@ subroutine save_gltf(this, filename)
if (iostat == 0) then
write(unit, '(A)') json
close(unit)
print *, "GLTF file '" // trim(filename) // "' created successfully!"
call log_info("GLTF file '" // trim(filename) // "' created successfully!")
else
print *, "Error: Failed to create GLTF file"
call log_error("Failed to create GLTF file")
end if
end if

Expand Down
Loading
Loading