Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4d02635
fix: Support NaN values for disconnected line segments
krystophny Jul 20, 2025
34f9636
test: Improve coverage for NaN line breaking
krystophny Jul 20, 2025
86ba82c
test: Comprehensive NaN line breaking coverage
krystophny Jul 20, 2025
6e468ce
fix: Correct array indexing in disconnected_lines example
krystophny Jul 20, 2025
957a741
feat: Add histogram plotting support with TDD
krystophny Jul 20, 2025
d2391c1
fix: Break long lines in fortplot_figure module
krystophny Jul 20, 2025
177208f
fix: Address code review feedback for histogram implementation
krystophny Jul 20, 2025
a75432c
fix: Update histogram demo to use FORD-compatible output directory an…
krystophny Jul 21, 2025
3d1fe8d
fix: refactor histogram routines for SOLID compliance and eliminate m…
krystophny Aug 16, 2025
58648dd
fix: Correct dependency name in fpm example
krystophny Aug 16, 2025
12cdbd8
fix: refactor remaining histogram routines for 30-line SOLID compliance
krystophny Aug 16, 2025
647f807
feat: expose histogram in main fortplot API for matplotlib compatibility
krystophny Aug 16, 2025
81e72a2
fix: refactor hist subroutine for SOLID compliance
krystophny Aug 16, 2025
b87d1b8
fix: address critical security and quality findings
krystophny Aug 16, 2025
7378999
docs: mark histogram feature as implemented in README
krystophny Aug 16, 2025
fffb5ac
fix: prevent segmentation faults in histogram with invalid bins param…
krystophny Aug 16, 2025
2208056
fix: update repository references from krystophny/fortplotlib to lazy…
krystophny Aug 17, 2025
5066b03
fix: remove binary files and build artifacts from workspace
krystophny Aug 17, 2025
80d4958
Merge main branch - resolve conflicts between histogram and boxplot f…
krystophny Aug 17, 2025
e6321d4
fix: update CMake example to use correct fortplot target names
krystophny Aug 17, 2025
401af92
fix: correct test executable name in CI and improve histogram plot in…
krystophny Aug 17, 2025
783c725
fix: move histogram test files from app/ to test/ directory for prope…
krystophny Aug 17, 2025
6c7cfd8
fix: resolve segmentation fault in global pyplot-style histogram func…
krystophny Aug 17, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,4 @@ jobs:
cd build
cmake ..
make
./fortplotlib_test
./fortplot_test
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ create_build_dirs:
@mkdir -p build/example/smart_show_demo
@mkdir -p build/example/animation
@mkdir -p build/example/stateful_streamplot
@mkdir -p build/example/histogram_demo
@mkdir -p build/example/subplot_demo

# Help target
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ![fortplot logo](media/logo.jpg)

[![codecov](https://codecov.io/gh/krystophny/fortplot/branch/main/graph/badge.svg)](https://codecov.io/gh/krystophny/fortplot)
[![Documentation](https://img.shields.io/badge/docs-FORD-blue.svg)](https://krystophny.github.io/fortplot/)
[![codecov](https://codecov.io/gh/lazy-fortran/fortplot/branch/main/graph/badge.svg)](https://codecov.io/gh/lazy-fortran/fortplot)
[![Documentation](https://img.shields.io/badge/docs-FORD-blue.svg)](https://lazy-fortran.github.io/fortplot/)

Fortran-native plotting inspired by Python's `matplotlib.pyplot` and https://github.com/jacobwilliams/pyplot-fortran . This library is under active development and API still subject to change. There are no external dependencies. Ironically, it has also Python interface installable via `pip` (see below) `fortplot.fortplot` that can be used as a drop-in replacement for `matplotlib.pyplot` for a limited set of features.

Expand Down Expand Up @@ -111,7 +111,7 @@ to build and run them.
Add to your `fpm.toml`:
```toml
[[dependencies]]
fortplot = { git = "https://github.com/krystophny/fortplot" }
fortplot = { git = "https://github.com/lazy-fortran/fortplot" }
```

### For CMake projects
Expand All @@ -122,7 +122,7 @@ include(FetchContent)

FetchContent_Declare(
fortplot
GIT_REPOSITORY https://github.com/krystophny/fortplot
GIT_REPOSITORY https://github.com/lazy-fortran/fortplot
GIT_TAG main
)
FetchContent_MakeAvailable(fortplot)
Expand All @@ -134,7 +134,7 @@ target_link_libraries(your_target fortplot::fortplot)
Install the Python package with pip:

```bash
pip install git+https://github.com/krystophny/fortplot.git
pip install git+https://github.com/lazy-fortran/fortplot.git
```

## Features
Expand All @@ -146,7 +146,7 @@ pip install git+https://github.com/krystophny/fortplot.git
- [x] Streamplots (`streamplot`) for vector field visualization
- [ ] Scatter plots (`scatter`)
- [ ] Bar charts (`bar`)
- [ ] Histograms (`hist`)
- [x] Histograms (`hist`)
- [ ] Images (`imshow`)

### Backends
Expand Down
12 changes: 6 additions & 6 deletions doc/cmake_example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ enable_language(Fortran)
# Include FetchContent module
include(FetchContent)

# Fetch and build fortplotlib using CMake
# Fetch and build fortplot using CMake
FetchContent_Declare(
fortplotlib
GIT_REPOSITORY https://github.com/krystophny/fortplot
fortplot
GIT_REPOSITORY https://github.com/lazy-fortran/fortplot
GIT_TAG main
)
FetchContent_MakeAvailable(fortplotlib)
FetchContent_MakeAvailable(fortplot)

# Create a simple test program
add_executable(fortplot_test main.f90)

# Link against fortplotlib (using old name until rename is merged to main)
target_link_libraries(fortplot_test fortplotlib::fortplotlib)
# Link against fortplot
target_link_libraries(fortplot_test fortplot::fortplot)

# Set Fortran compiler flags
set(CMAKE_Fortran_FLAGS "-Wall -Wextra -fimplicit-none")
Expand Down
2 changes: 1 addition & 1 deletion doc/fpm_example/fpm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ version = "0.1.0"
license = "MIT"

[dependencies]
fortplot = { path = "../.." }
fortplot = { git = "https://github.com/lazy-fortran/fortplot" }

2 changes: 1 addition & 1 deletion doc/python_example/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ build-backend = "setuptools.build_meta"
name = "fortplot-example"
version = "0.1.0"
dependencies = [
"fortplot @ git+https://github.com/krystophny/fortplot.git",
"fortplot @ git+https://github.com/lazy-fortran/fortplot.git",
"numpy"
]
2 changes: 1 addition & 1 deletion example/fortran/basic_plots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ The example generates the following output files:
- `simple_plot.png` - Simple sine wave visualization
- `multi_line.png` - Multiple functions on the same plot

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
2 changes: 1 addition & 1 deletion example/fortran/colored_contours/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ The example generates the following output files:
- `saddle_plasma.pdf` - Vector format of the saddle point
- `saddle_plasma.txt` - ASCII art of the saddle point pattern

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
2 changes: 1 addition & 1 deletion example/fortran/contour_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ The example generates the following output files:
- `mixed_plot.pdf` - Vector format of the mixed plot
- `mixed_plot.txt` - ASCII art representation of the mixed plot

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
66 changes: 66 additions & 0 deletions example/fortran/histogram_demo.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
program histogram_demo
!! Example demonstrating histogram plotting capabilities
!! Shows basic histogram, custom bins, and density normalization

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

integer, parameter :: n_data = 1000
real(wp) :: data(n_data), normal_data(n_data)
type(figure_t) :: fig
integer :: i
real(wp) :: pi = 3.14159265359_wp

! Generate random-like data (simple distribution)
do i = 1, n_data
data(i) = real(i, wp) / 100.0_wp + sin(real(i, wp) * 0.01_wp) * 5.0_wp
end do

! Generate normal-like data using Box-Muller transform approximation
do i = 1, n_data
normal_data(i) = cos(2.0_wp * pi * real(i, wp) / real(n_data, wp)) * &
sqrt(-2.0_wp * log(max(real(mod(i, 1000), wp) / 1000.0_wp, 0.001_wp)))
end do

! Basic histogram
call fig%initialize(800, 600)
call fig%hist(data)
call fig%set_title('Basic Histogram Example')
call fig%set_xlabel('Value')
call fig%set_ylabel('Frequency')
call fig%savefig('build/example/histogram_demo/histogram_basic.png')
write(*,*) 'Created histogram_basic.png'

! Custom bins histogram
call fig%initialize(800, 600)
call fig%hist(data, bins=20)
call fig%set_title('Histogram with 20 Bins')
call fig%set_xlabel('Value')
call fig%set_ylabel('Frequency')
call fig%savefig('build/example/histogram_demo/histogram_custom_bins.png')
write(*,*) 'Created histogram_custom_bins.png'

! Density histogram
call fig%initialize(800, 600)
call fig%hist(normal_data, bins=15, density=.true.)
call fig%set_title('Normalized Histogram (Density)')
call fig%set_xlabel('Value')
call fig%set_ylabel('Probability Density')
call fig%savefig('build/example/histogram_demo/histogram_density.png')
write(*,*) 'Created histogram_density.png'

! Multiple histograms with labels
call fig%initialize(800, 600)
call fig%hist(data(1:500), bins=15, label='Dataset 1', color=[0.0_wp, 0.447_wp, 0.698_wp])
call fig%hist(normal_data(1:500), bins=15, label='Dataset 2', color=[0.835_wp, 0.369_wp, 0.0_wp])
call fig%legend()
call fig%set_title('Multiple Histograms')
call fig%set_xlabel('Value')
call fig%set_ylabel('Frequency')
call fig%savefig('build/example/histogram_demo/histogram_multiple.png')
write(*,*) 'Created histogram_multiple.png'

write(*,*) 'Histogram demonstration completed!'

end program histogram_demo
2 changes: 1 addition & 1 deletion example/fortran/line_styles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ The example generates the following output files:
- `line_styles.pdf` - Vector format of the same visualization
- `line_styles.txt` - ASCII art representation of the line styles

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
2 changes: 1 addition & 1 deletion example/fortran/marker_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ The example generates the following output files:
- `marker_colors.pdf` - Vector format of colored markers
- `marker_colors.txt` - ASCII art with different marker representations

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
2 changes: 1 addition & 1 deletion example/fortran/pcolormesh_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ The example generates the following output files:
- `pcolormesh_sinusoidal.pdf` - Vector format of the sinusoidal pattern
- `pcolormesh_sinusoidal.txt` - ASCII representation of the sine wave pattern

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
2 changes: 1 addition & 1 deletion example/fortran/scale_examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ The example generates the following output files:
- `symlog_scale.pdf` - Vector format of the symlog scale plot
- `symlog_scale.txt` - ASCII art representation with symmetric log axes

See the [documentation gallery](https://krystophny.github.io/fortplot/) for visual examples.
See the [documentation gallery](https://lazy-fortran.github.io/fortplot/) for visual examples.
8 changes: 4 additions & 4 deletions example/generate_example_docs.f90
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,17 @@ subroutine write_source_links(unit_out, example_name)
select case(example_name)
case('animation')
fortran_file = 'save_animation_demo.f90'
fortran_path = 'https://github.com/krystophny/fortplot/blob/main/example/fortran/' // &
fortran_path = 'https://github.com/lazy-fortran/fortplot/blob/main/example/fortran/' // &
trim(example_name) // '/' // trim(fortran_file)
local_fortran_path = 'example/fortran/' // trim(example_name) // '/' // trim(fortran_file)
case('ascii_heatmap')
fortran_file = 'ascii_heatmap_demo.f90'
fortran_path = 'https://github.com/krystophny/fortplot/blob/main/example/fortran/' // &
fortran_path = 'https://github.com/lazy-fortran/fortplot/blob/main/example/fortran/' // &
trim(example_name) // '/' // trim(fortran_file)
local_fortran_path = 'example/fortran/' // trim(example_name) // '/' // trim(fortran_file)
case default
fortran_file = trim(example_name) // '.f90'
fortran_path = 'https://github.com/krystophny/fortplot/blob/main/example/fortran/' // &
fortran_path = 'https://github.com/lazy-fortran/fortplot/blob/main/example/fortran/' // &
trim(example_name) // '/' // trim(fortran_file)
local_fortran_path = 'example/fortran/' // trim(example_name) // '/' // trim(fortran_file)
end select
Expand All @@ -229,7 +229,7 @@ subroutine write_source_links(unit_out, example_name)
if (python_exists) then
write(unit_out, '(A)') ''
write(unit_out, '(A)') '🐍 **Python:** [' // trim(example_name) // &
'.py](https://github.com/krystophny/fortplot/blob/main/' // &
'.py](https://github.com/lazy-fortran/fortplot/blob/main/' // &
trim(python_path) // ')'
end if
write(unit_out, '(A)') ''
Expand Down
4 changes: 2 additions & 2 deletions scripts/generate_example_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ def generate_example_page(example_info, output_dir):
content += "### PDF Output\n\n"
for pdf in pdf_files:
pdf_name = Path(pdf).name
content += f"- [{pdf_name}](https://github.com/krystophny/fortplot/blob/main/{pdf})\n"
content += f"- [{pdf_name}](https://github.com/lazy-fortran/fortplot/blob/main/{pdf})\n"
content += "\n"

# Add link back to source
rel_source = os.path.relpath(source_file, '.')
content += f"""
---

Source: [{rel_source}](https://github.com/krystophny/fortplot/blob/main/{rel_source})
Source: [{rel_source}](https://github.com/lazy-fortran/fortplot/blob/main/{rel_source})
"""

# Write the markdown file
Expand Down
60 changes: 60 additions & 0 deletions src/fortplot.f90
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module fortplot
! Re-export public interface
public :: figure_t, wp
public :: plot, contour, contour_filled, pcolormesh, streamplot, boxplot, show, show_viewer
public :: hist, histogram
public :: xlabel, ylabel, title, legend
public :: savefig, figure
public :: add_plot, add_contour, add_contour_filled, add_pcolormesh
Expand Down Expand Up @@ -164,6 +165,57 @@ subroutine streamplot(x, y, u, v, density)
call fig%streamplot(x, y, u, v, density=density)
end subroutine streamplot

subroutine hist(data, bins, density, label, color)
!! Add histogram plot to the global figure (pyplot-style)
!!
!! Creates a histogram from input data, compatible with matplotlib.pyplot.hist
!!
!! Arguments:
!! data: Input data array to create histogram from
!! bins: Optional - number of bins (integer, default: 10)
!! density: Optional - normalize to probability density (default: false)
!! label: Optional - histogram label for legend
!! color: Optional - histogram color as RGB values [0-1]
!!
!! Example:
!! ! Simple histogram
!! call hist(data_values, bins=20, label='Distribution')
real(8), intent(in) :: data(:)
integer, intent(in), optional :: bins
logical, intent(in), optional :: density
character(len=*), intent(in), optional :: label
real(8), intent(in), optional :: color(3)

call ensure_global_figure_initialized()
call fig%hist(data, bins=bins, density=density, label=label, color=color)
end subroutine hist

subroutine histogram(data, bins, density, label, color)
!! Add histogram plot to the global figure (pyplot-style)
!!
!! Alias for hist() subroutine - creates a histogram from input data
!! Compatible with matplotlib.pyplot.histogram
!!
!! Arguments:
!! data: Input data array to create histogram from
!! bins: Optional - number of bins (integer, default: 10)
!! density: Optional - normalize to probability density (default: false)
!! label: Optional - histogram label for legend
!! color: Optional - histogram color as RGB values [0-1]
!!
!! Example:
!! ! Simple histogram
!! call histogram(data_values, bins=20, label='Distribution')
real(8), intent(in) :: data(:)
integer, intent(in), optional :: bins
logical, intent(in), optional :: density
character(len=*), intent(in), optional :: label
real(8), intent(in), optional :: color(3)

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

subroutine boxplot(data, position, width, label, show_outliers, horizontal, color)
!! Add a box plot to the global figure (matplotlib-style)
!!
Expand Down Expand Up @@ -544,4 +596,12 @@ subroutine show_viewer(blocking)
call show_viewer_implementation(blocking=blocking)
end subroutine show_viewer

subroutine ensure_global_figure_initialized()
!! Ensure global figure is initialized before use (matplotlib compatibility)
!! Auto-initializes with default dimensions if not already initialized
if (.not. allocated(fig%backend)) then
call fig%initialize()
end if
end subroutine ensure_global_figure_initialized

end module fortplot
6 changes: 4 additions & 2 deletions src/fortplot_figure.f90
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ module fortplot_figure
!! Re-exports: utility functions from fortplot_utils

use fortplot_figure_core, only: figure_t, plot_data_t, PLOT_TYPE_LINE, &
PLOT_TYPE_CONTOUR, PLOT_TYPE_PCOLORMESH, PLOT_TYPE_BOXPLOT
PLOT_TYPE_CONTOUR, PLOT_TYPE_PCOLORMESH, &
PLOT_TYPE_HISTOGRAM, PLOT_TYPE_BOXPLOT
use fortplot_scales, only: apply_scale_transform, apply_inverse_scale_transform, &
transform_x_coordinate, transform_y_coordinate
use fortplot_utils, only: get_backend_from_filename, initialize_backend
Expand All @@ -19,7 +20,8 @@ module fortplot_figure

! Re-export all public entities for backward compatibility
public :: figure_t, plot_data_t
public :: PLOT_TYPE_LINE, PLOT_TYPE_CONTOUR, PLOT_TYPE_PCOLORMESH, PLOT_TYPE_BOXPLOT
public :: PLOT_TYPE_LINE, PLOT_TYPE_CONTOUR, PLOT_TYPE_PCOLORMESH, &
PLOT_TYPE_HISTOGRAM, PLOT_TYPE_BOXPLOT
public :: apply_scale_transform, apply_inverse_scale_transform
public :: transform_x_coordinate, transform_y_coordinate
public :: get_backend_from_filename, initialize_backend
Expand Down
Loading