Skip to content

Repository files navigation

fplot

A Fortran library providing a convenient interface for plotting with Gnuplot.

Status

Build Status Actions Status

GNUPLOT

This library is tailored to write script files for GNUPLOT. As such, GNUPLOT is required to make use of the output of this library. GNUPLOT can be found here.

Documentation

Documentation can be found here

Building

FPLOT requires a Fortran compiler with Fortran 2003 support and Gnuplot on your PATH to render plots. The CMake and FPM builds retrieve the Fortran library dependencies automatically.

CMake

Configure and build the library with CMake 3.24 or newer:

cmake -S . -B build -DBUILD_TESTING=ON -DBUILD_FPLOT_EXAMPLES=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failure

Install it to a prefix of your choice:

cmake --install build --prefix /path/to/install

To build a shared library, add -DBUILD_SHARED_LIBS=ON to the configure command. Set BUILD_TESTING or BUILD_FPLOT_EXAMPLES to OFF when those targets are not needed.

FPM

FPM can build and test the checked-out repository directly:

fpm build
fpm test

Add FPLOT to another FPM project with:

[dependencies]
fplot = { git = "https://github.com/jchristopherson/fplot" }

Getting Started

Import fplot_core for the primary types, styling constants, and helper routines such as linspace and meshgrid. A basic 2D plot follows four steps: initialize a plot object, configure its appearance, add one or more data series, and draw it.

use, intrinsic :: iso_fortran_env
use fplot_core

type(plot_2d) :: plt
real(real64) :: x(100), y(100)

x = linspace(0.0_real64, 10.0_real64, size(x))
y = sin(x)

call plt%initialize()
call plt%set_title("Sine wave")
call plt%set_x_axis_title("x")
call plt%set_y_axis_title("sin(x)")
call plt%push(x, y, lw = 2.0, name = "sin(x)")
call plt%draw()

plot_2d%push creates a line data series directly from x and y. For more control, create a plot_data_2d object, call define_data, set properties such as its name, line style, markers, or color, and then pass it to plot_2d%push.

Use plot_3d for 3D curves and scatter data, surface_plot for gridded surfaces, and plot_polar for polar coordinates. plot_data_error_bars, plot_data_histogram, plot_data_bar, and vector_field_plot_data provide specialized series types. Axis and legend objects are available through get_x_axis, get_y_axis, and get_legend for detailed layout control. Invalid input and allocation failures print a diagnostic and terminate with an fplot_errors error code.

The examples directory contains complete programs for 2D and 3D plots, surfaces, histograms, error bars, vector fields, and output terminals.

External Libraries

The FPLOT library depends upon the following libraries.

Example 1

This example illustrates how to plot two-dimensional data.

program example
    use, intrinsic :: iso_fortran_env
    use fplot_core
    implicit none

    ! Parameters
    integer(int32), parameter :: n = 1000

    ! Local Variables
    real(real64), dimension(n) :: x, y1, y2
    type(plot_2d) :: plt
    
    ! Initialize the plot object
    call plt%initialize()
    call plt%show_legend(.true.)
    call plt%set_title("Example Plot")
    call plt%set_x_axis_title("X Axis")
    call plt%set_y_axis_title("Y Axis")

    ! Define the data, and then add it to the plot
    x = linspace(0.0d0, 10.0d0, n)
    y1 = sin(5.0d0 * x)
    y2 = 2.0d0 * cos(2.0d0 * x)

    call plt%push(x, y1, lw = 2.0, name = "Data Set 1")
    call plt%push(x, y2, lw = 2.0, ls = LINE_DASHED, name = "Data Set 2")
    
    ! Let GNUPLOT draw the plot
    call plt%draw()
end program

This is the plot resulting from the above program.

Example 2

Another example of a similar two-dimensional plot to the plot in example 1 is given below. This plot shifts the x-axis to the zero point along the y-axis. Additionally, this example highlights the use of the plot_axis, legend, and plot_data_2d types to gain more control over the plot.

program example
    use, intrinsic :: iso_fortran_env
    use fplot_core
    implicit none

    ! Parameters
    integer(int32), parameter :: n = 1000

    ! Local Variables
    real(real64), dimension(n) :: x, y1, y2
    type(plot_2d) :: plt
    type(plot_data_2d) :: d1, d2
    class(plot_axis), pointer :: xAxis, yAxis
    type(legend), pointer :: lgnd
    
    ! Initialize the plot object
    call plt%initialize()
    
    ! Set plot properties
    call plt%set_draw_border(.false.)
    call plt%set_show_gridlines(.false.)

    ! Define the legend location
    lgnd => plt%get_legend()
    call lgnd%set_is_visible(.true.)
    call lgnd%set_draw_inside_axes(.false.)

    ! Define titles
    call plt%set_title("2D Example Plot 2")

    xAxis => plt%get_x_axis()
    call xAxis%set_title("X Axis")
    call xAxis%set_zero_axis(.true.)
    call xAxis%set_zero_axis_line_width(1.0)

    yAxis => plt%get_y_axis()
    call yAxis%set_title("Y Axis")

    ! Define the data, and then add it to the plot
    x = linspace(0.0d0, 10.d0, n)
    y1 = sin(5.0d0 * x)
    y2 = 2.0d0 * cos(2.0d0 * x)

    call d1%define_data(x, y1)
    call d2%define_data(x, y2)

    ! Define properties for each data set
    call d1%set_name("Data Set 1")
    call d1%set_line_width(1.0)

    call d2%set_name("Data Set 2")
    call d2%set_line_style(LINE_DASHED)
    call d2%set_line_width(2.0)

    ! Add the data sets to the plot
    call plt%push(d1)
    call plt%push(d2)

    ! Let GNUPLOT draw the plot
    call plt%draw()
end program

This is the plot resulting from the above program.

Example 3

The following example illustrates how to create a three-dimensional surface plot. The plot also leverages the FORCOLORMAP library to provide the colormap.

program example
    use fplot_core
    use iso_fortran_env
    use forcolormap
    implicit none

    ! Parameters
    integer(int32), parameter :: m = 50
    integer(int32), parameter :: n = 50

    ! Local Variables
    real(real64), dimension(m, n, 2), target :: xy
    real(real64), pointer, dimension(:,:) :: x, y
    real(real64), dimension(m, n) :: z
    type(surface_plot) :: plt
    type(custom_colormap) :: map
    type(cmap) :: colors

    ! Set up the colormap
    call colors%set("glasgow", -8.0d0, 8.0d0)
    call map%set_colormap(colors)

    ! Define the data
    xy = meshgrid(linspace(-5.0d0, 5.0d0, n), linspace(-5.0d0, 5.0d0, m))
    x => xy(:,:,1)
    y => xy(:,:,2)

    ! Initialize the plot
    call plt%initialize()
    call plt%set_colormap(map)
    call plt%set_x_axis_title("X Axis")
    call plt%set_y_axis_title("Y Axis")
    call plt%set_z_axis_title("Z Axis")
    call plt%set_title("Custom Colormap")

    ! Establish lighting
    call plt%set_use_lighting(.true.)

    ! Set the orientation of the plot
    call plt%set_elevation(20.0d0)
    call plt%set_azimuth(30.0d0)

    ! Define the function to plot
    z = sqrt(x**2 + y**2) * sin(x**2 + y**2)
    call plt%push(x, y, z)

    ! Draw the plot
    call plt%draw()
end program

This is the plot resulting from the above program.

Example 4

The following example illustrates how to create a vector-field plot. This example illustrates using one of the built-in colormaps to to help illustrate vector magnitude.

program example
    use iso_fortran_env
    use fplot_core
    implicit none

    ! Local Variables
    type(plot_2d) :: plt
    type(vector_field_plot_data) :: ds1
    class(plot_axis), pointer :: xAxis, yAxis
    type(rainbow_colormap) :: cmap
    real(real64), allocatable, dimension(:,:,:) :: pts
    real(real64), allocatable, dimension(:,:) :: dx, dy
    real(real64) :: dxdt(2)
    integer(int32) :: i, j

    ! Create a grid of points defining the vector locations
    pts = meshgrid( &
        linspace(-2.0d0, 2.0d0, 20), &
        linspace(-5.0d0, 5.0d0, 20))

    ! Compute the values of each derivative
    allocate(dx(size(pts, 1), size(pts, 2)))
    allocate(dy(size(pts, 1), size(pts, 2)))
    do j = 1, size(pts, 2)
        do i = 1, size(pts, 1)
            call eqn([pts(i,j,1), pts(i,j,2)], dxdt)
            dx(i,j) = dxdt(1)
            dy(i,j) = dxdt(2)
        end do
    end do

    ! Define arrow properties
    call ds1%set_arrow_size(0.1d0)  ! 1.0 by default
    call ds1%set_fill_arrow(.true.) ! .false. by default

    ! Create the plot
    call plt%initialize()
    xAxis => plt%get_x_axis()
    yAxis => plt%get_y_axis()

    ! Define axis labels
    call xAxis%set_title("x(t)")
    call yAxis%set_title("dx/dt")

    ! Set plot style information
    call xAxis%set_zero_axis(.true.)
    call yAxis%set_zero_axis(.true.)
    call plt%set_draw_border(.false.)
    call plt%set_show_gridlines(.false.)

    ! Define the colormap
    call plt%set_colormap(cmap)

    ! Add the data to the plot - color by the magnitude of gradient
    call ds1%define_data(pts(:,:,1), pts(:,:,2), dx, dy, sqrt(dx**2 + dy**2))
    call plt%push(ds1)

    call plt%draw()
contains
    ! Van der Pol Equation
    ! x" - mu * (1 - x^2) * x' + x = 0
    subroutine eqn(x, dxdt)
        real(real64), intent(in) :: x(2)
        real(real64), intent(out) :: dxdt(2)

        real(real64), parameter :: mu = 2.0d0

        dxdt(1) = x(2)
        dxdt(2) = mu * (1.0d0 - x(1)**2) * x(2) - x(1)
    end subroutine
end program

This is the plot resulting from the above program.

Example 5

The following example illustrates how to create a polar plot.

program example
    use iso_fortran_env
    use fplot_core

    ! Local Variables
    integer(int32), parameter :: npts = 1000
    real(real64), parameter :: pi = 2.0d0 * acos(0.0d0)
    real(real64) :: t(npts), x(npts)
    type(plot_polar) :: plt

    ! Create a function to plot
    t = linspace(-2.0d0 * pi, 2.0d0 * pi, npts)
    x = t * sin(t)

    ! Plot the function
    call plt%initialize()
    call plt%set_font_size(14)
    call plt%set_title("Polar Plot Example")
    call plt%set_autoscale(.false.)
    call plt%set_radial_limits([0.0d0, 6.0d0])
    call plt%push(t, x, lw = 2.0)
    call plt%draw()
end program

This is the plot resulting from the above program.

About

A Fortran library providing a convenient interface for plotting with Gnuplot.

Topics

Resources

Stars

43 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages