! fplot_plot_data.f90

module fplot_plot_data
    use iso_fortran_env
    use fplot_plot_object
    use fplot_constants
    use fplot_colors
    use strings
    use ferror
    use fplot_errors
    implicit none
    private
    public :: plot_data
    public :: pd_get_string_result
    public :: pd_clear_action
    public :: plot_data_colored
    public :: scatter_plot_data
    public :: line_plot_data
    public :: spd_get_int_value
    public :: spd_get_string_result
    public :: spd_get_value
    public :: spd_set_value
    public :: lpd_get_cmd
    public :: spd_get_cmd

    type, abstract, extends(plot_object) :: plot_data
        !! A container for plot data.
    private
        character(len = PLOTDATA_MAX_NAME_LENGTH) :: m_name = ""
            !! The name to associate with the data set.
        character(len = PLOTDATA_MAX_NAME_LENGTH) :: m_datablockName = ""
            !! The name to associate with the datablock used to store the data
            !! in the actual plot file.
    contains
        procedure, public :: get_name => pd_get_name
        procedure, public :: set_name => pd_set_name
        procedure, public :: get_datablock_name => pd_get_datablock_name
        procedure, public :: set_datablock_name => pd_set_datablock_name
        procedure, public :: create_unique_datablock_name => &
            pd_create_unique_datablock_name
        procedure, public :: clear_all => pd_clear
        procedure(pd_get_string_result), deferred, public :: get_data_string
        procedure(pd_clear_action), deferred, public :: clear_data
    end type

    interface
        function pd_get_string_result(this) result(x)
            !! Retrieves a string from a plot_data object.
            import plot_data
            class(plot_data), intent(in) :: this
                !! The plot_data object.
            character(len = :), allocatable :: x
                !! The string.
        end function

        subroutine pd_clear_action(this)
            !! Performs a clearing operation.
            import plot_data
            class(plot_data), intent(inout) :: this
                !! The plot_data object.
        end subroutine
    end interface

    type, abstract, extends(plot_data) :: plot_data_colored
        !! Defines a colored plot data set.
    private
        type(color) :: m_color = CLR_BLUE
            !! The line color.
        logical :: m_useAutoColor = .true.
            !! Let the object choose colors automatically?
        integer(int32) :: m_colorIndex = 1
            !! The color index to use, assuming we're using auto color
    contains
        procedure, public :: get_line_color => pdc_get_line_color
        procedure, public :: set_line_color => pdc_set_line_color
        procedure, public :: get_color_index => pdc_get_color_index
        procedure, public :: set_color_index => pdc_set_color_index
    end type

    type, abstract, extends(plot_data_colored) :: line_plot_data
        !! A plot_data object for describing line series data.
        logical, private :: m_drawLine = .true.
            !! Draw a line connecting the dots?
        logical, private :: m_drawMarkers = .false.
            !! Draw the markers?
        real(real32), private :: m_lineWidth = 1.0
            !! Line width.
        integer(int32), private :: m_lineStyle = LINE_SOLID
            !! Line style.
        integer(int32), private :: m_markerType = MARKER_FILLED_CIRCLE
            !! Marker type.
        real(real32), private :: m_markerSize = 0.5
            !! Marker size multiplier.
        integer(int32), private :: m_markerFrequency = 1
            !! Marker frequency.
    contains
        procedure, public :: get_command_string => lpd_get_cmd
        procedure, public :: get_line_width => lpd_get_line_width
        procedure, public :: set_line_width => lpd_set_line_width
        procedure, public :: get_line_style => lpd_get_line_style
        procedure, public :: set_line_style => lpd_set_line_style
        procedure, public :: get_draw_line => lpd_get_draw_line
        procedure, public :: set_draw_line => lpd_set_draw_line
        procedure, public :: get_draw_markers => lpd_get_draw_markers
        procedure, public :: set_draw_markers => lpd_set_draw_markers
        procedure, public :: get_marker_style => lpd_get_marker_style
        procedure, public :: set_marker_style => lpd_set_marker_style
        procedure, public :: get_marker_scaling => lpd_get_marker_scaling
        procedure, public :: set_marker_scaling => lpd_set_marker_scaling
        procedure, public :: get_marker_frequency => lpd_get_marker_frequency
        procedure, public :: set_marker_frequency => lpd_set_marker_frequency
    end type

    type, abstract, extends(line_plot_data) :: scatter_plot_data
        !! A plot_data object for describing scatter plot data sets.
        logical, private :: m_simplifyData = .true.
            !! True if large data sets should be simplified before sending to
            !! GNUPLOT.
        real(real64), private :: m_simplifyFactor = 1.0d-3
            !! A scaling factor used to establish the simplification tolerance.
            !! The simplification tolerance is established by multiplying this
            !! factor by the range in the dependent variable data.
        logical, private :: m_dataDependentColors = .false.
            !! Determines if the data should utilize data-dependent colors.
        logical, private :: m_filledCurve = .false.
            !! Fill the curve?
        logical, private :: m_useVariableSizePoints = .false.
            !! Use variable size data points?
    contains
        procedure, public :: get_command_string => spd_get_cmd
        procedure(spd_get_int_value), deferred, public :: get_count
        procedure(spd_get_value), deferred, public :: get_x
        procedure(spd_set_value), deferred, public :: set_x
        procedure(spd_get_value), deferred, public :: get_y
        procedure(spd_set_value), deferred, public :: set_y
        procedure(spd_get_string_result), deferred, public :: get_axes_string
        procedure, public :: get_simplify_data => spd_get_simplify_data
        procedure, public :: set_simplify_data => spd_set_simplify_data
        procedure, public :: get_simplification_factor => spd_get_simplify_factor
        procedure, public :: set_simplification_factor => spd_set_simplify_factor
        procedure, public :: get_use_data_dependent_colors => &
            spd_get_data_dependent_colors
        procedure, public :: set_use_data_dependent_colors => &
            spd_set_data_dependent_colors
        procedure, public :: get_fill_curve => spd_get_filled
        procedure, public :: set_fill_curve => spd_set_filled
        procedure, public :: get_use_variable_size_points => spd_get_use_var_point_size
        procedure, public :: set_use_variable_size_points => spd_set_use_var_point_size
    end type

    interface
        pure function spd_get_value(this, index) result(x)
            !! Gets an indexed value from the scatter_plot_data object.
            use, intrinsic :: iso_fortran_env, only : int32, real64
            import scatter_plot_data
            class(scatter_plot_data), intent(in) :: this
                !! The scatter_plot_data object.
            integer(int32), intent(in) :: index
                !! The index.
            real(real64) :: x
                !! The value.
        end function

        subroutine spd_set_value(this, index, x)
            !! Sets an indexed value from the scatter_plot_data object.
            use, intrinsic :: iso_fortran_env, only : int32, real64
            import scatter_plot_data
            class(scatter_plot_data), intent(inout) :: this
                !! The scatter_plot_data object.
            integer(int32), intent(in) :: index
                !! The index.
            real(real64), intent(in) :: x
                !! The value.
        end subroutine

        pure function spd_get_int_value(this) result(x)
            !! Gets an integer value from the scatter_plot_data object.
            use, intrinsic :: iso_fortran_env, only : int32
            import scatter_plot_data
            class(scatter_plot_data), intent(in) :: this
                !! The scatter_plot_data object.
            integer(int32) :: x
                !! The value.
        end function

        function spd_get_string_result(this) result(x)
            !! Gets a string value from the scatter_plot_data object.
            import scatter_plot_data
            class(scatter_plot_data), intent(in) :: this
                !! The scatter_plot_data object.
            character(len = :), allocatable :: x
                !! The string.
        end function
    end interface

contains
! ------------------------------------------------------------------------------
    pure function pd_get_name(this) result(txt)
        !! Gets the name to associate with this data set.
        class(plot_data), intent(in) :: this
            !! The plot_data object.
        character(len = :), allocatable :: txt
            !! The name.
        txt = trim(this%m_name)
    end function

! --------------------
    subroutine pd_set_name(this, txt)
        !! Sets the name to associate with this data set.
        class(plot_data), intent(inout) :: this
            !! The plot_data object.
        character(len = *), intent(in) :: txt
            !! The name.
        integer(int32) :: n
        n = min(len(txt), PLOTDATA_MAX_NAME_LENGTH)
        this%m_name = ""
        if (n /= 0) then
            this%m_name(1:n) = txt(1:n)
        end if
    end subroutine

! ------------------------------------------------------------------------------
    pure function pd_get_datablock_name(this) result(rst)
        !! Gets the name to associate with the datablock in the actual GNUPLOT
        !! plot file.
        class(plot_data), intent(in) :: this
            !! The plot_data object.
        character(len = :), allocatable :: rst
            !! The name.
        
        rst = trim(this%m_datablockName)
    end function

! --------------------
    subroutine pd_set_datablock_name(this, x)
        !! Sets the name to associate with the datablock in the actual GNUPLOT
        !! plot file.
        class(plot_data), intent(inout) :: this
            !! The plot_data object.
        character(len = *), intent(in) :: x
            !! The name.

        integer(int32) :: n
        n = min(len(x), PLOTDATA_MAX_NAME_LENGTH)
        this%m_datablockName = ""
        if (n /= 0) then
            this%m_datablockName(1:n) = x(1:n)
        end if
    end subroutine

! ------------------------------------------------------------------------------
    subroutine pd_create_unique_datablock_name(this)
        !! Creates a unique name for the GNUPLOT datablock representing this
        !! data set.
        class(plot_data), intent(inout) :: this
            !! The plot_data object.

        type(string) :: str
        real(real64) :: r, rng
        integer(int32) :: count

        call random_seed()
        call random_number(r)
        r = r * huge(count)
        count = floor(r)
        str = "PlotData" // to_string(count)
        call this%set_datablock_name(char(str))
    end subroutine

! ------------------------------------------------------------------------------
    subroutine pd_clear(this)
        !! Clears the data set by removing stored data and clearing the 
        !! GNUPLOT datablock name.  This routine also calls clear_data to
        !! ensure the data is cleared from the data set as well as the datablock
        !! name.
        class(plot_data), intent(inout) :: this
            !! The plot_data object.

        call this%set_datablock_name("")
        call this%clear_data()
    end subroutine

! ******************************************************************************
! PLOT_DATA_COLORED
! ------------------------------------------------------------------------------
    pure function pdc_get_line_color(this) result(x)
        !! Gets the object color.
        class(plot_data_colored), intent(in) :: this
            !! The plot_data_colored object.
        type(color) :: x
            !! The color.
        if (this%m_useAutoColor) then
            x = color_list(this%get_color_index())
        else
            x = this%m_color
        end if
    end function

! --------------------
    subroutine pdc_set_line_color(this, x)
        !! Sets the object color.
        class(plot_data_colored), intent(inout) :: this
            !! The plot_data_colored object.
        type(color), intent(in) :: x
            !! The color.
        this%m_color = x
        this%m_useAutoColor = .false.
    end subroutine

! ------------------------------------------------------------------------------
    pure function pdc_get_color_index(this) result(x)
        !! Gets the color index.
        class(plot_data_colored), intent(in) :: this
            !! The plot_data_colored object.
        integer(int32) :: x
            !! The index value.
        x = this%m_colorIndex
    end function

! --------------------
    subroutine pdc_set_color_index(this, x)
        !! Sets the color index.
        class(plot_data_colored), intent(inout) :: this
            !! The plot_data_colored object.
        integer(int32), intent(in) :: x
            !! The index value.
        this%m_colorIndex = x
    end subroutine

! ******************************************************************************
! LINE_PLOT_DATA
! ------------------------------------------------------------------------------
    pure function lpd_get_line_width(this) result(x)
        !! Gets the width of the line, in pixels.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        real(real32) :: x
            !! The line width.
        x = this%m_lineWidth
    end function

! --------------------
    subroutine lpd_set_line_width(this, x)
        !! Sets the width of the line, in pixels.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        real(real32), intent(in) :: x
            !! The line width.
        this%m_lineWidth = x
    end subroutine

! ------------------------------------------------------------------------------
    pure function lpd_get_line_style(this) result(x)
        !! Gets the line style.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        integer(int32) :: x
            !! The line style.  The line style must be one of the following.
            !!
            !!  - LINE_DASHED
            !!
            !!  - LINE_DASH_DOTTED
            !!
            !!  - LINE_DASH_DOT_DOT
            !!
            !!  - LINE_DOTTED
            !!
            !!  - LINE_SOLID
        x = this%m_lineStyle
    end function

! --------------------
    subroutine lpd_set_line_style(this, x)
        !! Sets the line style.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        integer(int32), intent(in) :: x
            !! The line style.  The line style must be one of the following.
            !!
            !!  - LINE_DASHED
            !!
            !!  - LINE_DASH_DOTTED
            !!
            !!  - LINE_DASH_DOT_DOT
            !!
            !!  - LINE_DOTTED
            !!
            !!  - LINE_SOLID
        if (x == LINE_DASHED .or. &
            x == LINE_DASH_DOTTED .or. &
            x == LINE_DASH_DOT_DOT .or. &
            x == LINE_DOTTED .or. &
            x == LINE_SOLID) then
            ! Only reset the line style if it is a valid type.
            this%m_lineStyle = x
        end if
    end subroutine

! ------------------------------------------------------------------------------
    pure function lpd_get_draw_line(this) result(x)
        !! Gets a value determining if a line should be drawn.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        logical :: x
            !! Returns true if the line should be drawn; else, false.
        x = this%m_drawLine
    end function

! --------------------
    subroutine lpd_set_draw_line(this, x)
        !! Sets a value determining if a line should be drawn.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        logical, intent(in) :: x
            !! Set to true if the line should be drawn; else, false.
        this%m_drawLine = x
    end subroutine

! ------------------------------------------------------------------------------
    pure function lpd_get_draw_markers(this) result(x)
        !! Gets a value determining if data point markers should be drawn.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        logical :: x
            !! Returns true if the markers should be drawn; else, false.
        x = this%m_drawMarkers
    end function

! --------------------
    subroutine lpd_set_draw_markers(this, x)
        !! Sets a value determining if data point markers should be drawn.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        logical, intent(in) :: x
            !! Set to true if the markers should be drawn; else, false.
        this%m_drawMarkers = x
    end subroutine

! ------------------------------------------------------------------------------
    pure function lpd_get_marker_style(this) result(x)
        !! Gets the marker style.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        integer(int32) :: x
            !! The marker type.  The marker type must be one of the following:
            !!
            !!  - MARKER_ASTERISK
            !!
            !!  - MARKER_EMPTY_CIRCLE
            !!
            !!  - MARKER_EMPTY_NABLA
            !!
            !!  - MARKER_EMPTY_RHOMBUS
            !!
            !!  - MARKER_EMPTY_SQUARE
            !!
            !!  - MARKER_EMPTY_TRIANGLE
            !!
            !!  - MARKER_FILLED_CIRCLE
            !!
            !!  - MARKER_FILLED_NABLA
            !!
            !!  - MARKER_FILLED_RHOMBUS
            !!
            !!  - MARKER_FILLED_SQUARE
            !!
            !!  - MARKER_FILLED_TRIANGLE
            !!
            !!  - MARKER_PLUS
            !!
            !!  - MARKER_X
        x = this%m_markerType
    end function

! --------------------
    subroutine lpd_set_marker_style(this, x)
        !! Sets the marker style.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        integer(int32), intent(in) :: x
            !! The marker type.  The marker type must be one of the following:
            !!
            !!  - MARKER_ASTERISK
            !!
            !!  - MARKER_EMPTY_CIRCLE
            !!
            !!  - MARKER_EMPTY_NABLA
            !!
            !!  - MARKER_EMPTY_RHOMBUS
            !!
            !!  - MARKER_EMPTY_SQUARE
            !!
            !!  - MARKER_EMPTY_TRIANGLE
            !!
            !!  - MARKER_FILLED_CIRCLE
            !!
            !!  - MARKER_FILLED_NABLA
            !!
            !!  - MARKER_FILLED_RHOMBUS
            !!
            !!  - MARKER_FILLED_SQUARE
            !!
            !!  - MARKER_FILLED_TRIANGLE
            !!
            !!  - MARKER_PLUS
            !!
            !!  - MARKER_X
        if (x == MARKER_ASTERISK .or. &
            x == MARKER_EMPTY_CIRCLE .or. &
            x == MARKER_EMPTY_NABLA .or. &
            x == MARKER_EMPTY_RHOMBUS .or. &
            x == MARKER_EMPTY_SQUARE .or. &
            x == MARKER_EMPTY_TRIANGLE .or. &
            x == MARKER_FILLED_CIRCLE .or. &
            x == MARKER_FILLED_NABLA .or. &
            x == MARKER_FILLED_RHOMBUS .or. &
            x == MARKER_FILLED_SQUARE .or. &
            x == MARKER_FILLED_TRIANGLE .or. &
            x == MARKER_PLUS .or. &
            x == MARKER_X) then

            ! Only alter the value if the marker is a known type
            this%m_markerType = x
        end if
    end subroutine

! ------------------------------------------------------------------------------
    pure function lpd_get_marker_scaling(this) result(x)
        !! Gets the marker scaling.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        real(real32) :: x
            !! The scaling factor.
        x = this%m_markerSize
    end function

! --------------------
    subroutine lpd_set_marker_scaling(this, x)
        !! Sets the marker scaling.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        real(real32), intent(in) :: x
            !! The scaling factor.
        this%m_markerSize = x
    end subroutine

! ------------------------------------------------------------------------------
    pure function lpd_get_marker_frequency(this) result(x)
        !! Gets the marker frequency.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        integer(int32) :: x
            !! The marker frequency.
        x = this%m_markerFrequency
    end function

! --------------------
    subroutine lpd_set_marker_frequency(this, x)
        !! Sets the marker frequency.
        class(line_plot_data), intent(inout) :: this
            !! The line_plot_data object.
        integer(int32), intent(in) :: x
            !! The marker frequency.
        this%m_markerFrequency = x
    end subroutine

! ------------------------------------------------------------------------------
    function lpd_get_cmd(this) result(rst)
        !! Gets the GNUPLOT command string to represent this line_plot_data
        !! object.
        class(line_plot_data), intent(in) :: this
            !! The line_plot_data object.
        character(len = :), allocatable :: rst
            !! The command string.

        ! Local Variables
        type(string_builder) :: str
        integer(int32) :: n
        type(color) :: clr

        ! Initialization
        call str%initialize()

        ! Title
        n = len_trim(this%get_name())
        if (n > 0) then
            call str%append(' title "')
            call str%append(this%get_name())
            call str%append('"')
        else
            call str%append(' notitle')
        end if

        ! Lines or points
        if (this%get_draw_line() .and. this%get_draw_markers()) then
            call str%append(" with linespoints")
        else if (.not.this%get_draw_line() .and. this%get_draw_markers()) then
            call str%append(" with points")
        else
            call str%append(" with lines")
        end if

        ! Line Width
        call str%append(" lw ")
        call str%append(to_string(this%get_line_width()))

        ! Line Color
        clr = this%get_line_color()
        call str%append(' lc rgb "#')
        call str%append(clr%to_hex_string())
        call str%append('"')

        ! Define other properties specific to the lines and points
        if (this%get_draw_line()) then
            call str%append(" lt ")
            call str%append(to_string(this%get_line_style()))
            if (this%get_line_style() /= LINE_SOLID) then
                call str%append(" dashtype ")
                call str%append(to_string(this%get_line_style()))
            end if
        end if
        if (this%get_draw_markers()) then
            call str%append(" pi ")
            call str%append(to_string(this%get_marker_frequency()))
            call str%append(" pt ")
            call str%append(to_string(this%get_marker_style()))
            call str%append(" ps ")
            call str%append(to_string(this%get_marker_scaling()))
        end if

        ! End
        rst = char(str%to_string())
    end function

! ******************************************************************************
! SCATTER_PLOT_DATA
! ------------------------------------------------------------------------------
    function spd_get_cmd(this) result(x)
        !! Gets the GNUPLOT command string to represent this
        !! scatter_plot_data object.
        class(scatter_plot_data), intent(in) :: this
            !! The scatter_plot_data object.
        character(len = :), allocatable :: x
            !! The command string.

        ! Local Variables
        type(string_builder) :: str
        integer(int32) :: n
        type(color) :: clr

        ! Initialization
        call str%initialize()

        ! Data Block
        call str%append(" $")
        call str%append(this%get_datablock_name())

        ! Title
        n = len_trim(this%get_name())
        if (n > 0) then
            call str%append(' title "')
            call str%append(this%get_name())
            call str%append('"')
        else
            call str%append(' notitle')
        end if

        ! Lines, points, or filled
        if (this%get_fill_curve()) then
            call str%append(" with filledcurves")
        else
            if (this%get_draw_line() .and. this%get_draw_markers()) then
                call str%append(" with linespoints")
            else if (.not.this%get_draw_line() .and. this%get_draw_markers()) then
                call str%append(" with points")
            else
                call str%append(" with lines")
            end if
        end if

        ! Line Width
        call str%append(" lw ")
        call str%append(to_string(this%get_line_width()))

        ! Line Color
        if (this%get_use_data_dependent_colors()) then
            ! http://www.gnuplotting.org/using-a-palette-as-line-color/
            call str%append(" lc palette")
        else
            clr = this%get_line_color()
            call str%append(' lc rgb "#')
            call str%append(clr%to_hex_string())
            call str%append('"')
        end if

        ! Define other properties specific to the lines and points
        if (this%get_draw_line()) then
            call str%append(" lt ")
            call str%append(to_string(this%get_line_style()))
            if (this%get_line_style() /= LINE_SOLID) then
                call str%append(" dashtype ")
                call str%append(to_string(this%get_line_style()))
            end if
        end if
        if (this%get_draw_markers()) then
            call str%append(" pi ")
            call str%append(to_string(this%get_marker_frequency()))
            call str%append(" pt ")
            call str%append(to_string(this%get_marker_style()))
            call str%append(" ps ")
            if (this%get_use_variable_size_points()) then
                call str%append("variable")
            else
                call str%append(to_string(this%get_marker_scaling()))
            end if
        end if

        ! Define the axes structure
        call str%append(" ")
        call str%append(this%get_axes_string())

        ! End
        x = char(str%to_string())
    end function

! ------------------------------------------------------------------------------
    pure function spd_get_simplify_data(this) result(x)
        !! Gets a value determining if the stored data should be
        !! simplified (reduced) before passing to GNUPLOT.
        class(scatter_plot_data), intent(in) :: this
            !! The scatter_plot_data object.
        logical :: x
            !! True if the data should be simplified prior to sending
            !! to GNUPLOT; else, false to leave the data alone.
        x = this%m_simplifyData
    end function

! --------------------
    subroutine spd_set_simplify_data(this, x)
        !! Sets a value determining if the stored data should be
        !! simplified (reduced) before passing to GNUPLOT.
        class(scatter_plot_data), intent(inout) :: this
            !! The scatter_plot_data object.
        logical, intent(in) :: x
            !! True if the data should be simplified prior to sending
            !! to GNUPLOT; else, false to leave the data alone.
        this%m_simplifyData = x
    end subroutine

! ------------------------------------------------------------------------------
    pure function spd_get_simplify_factor(this) result(x)
        !! Gets a factor used to establish the simplification tolerance.
        class(scatter_plot_data), intent(in) :: this
            !! The scatter_plot_data object.
        real(real64) :: x
            !! The scaling factor.
        x = this%m_simplifyFactor
    end function

! --------------------
    subroutine spd_set_simplify_factor(this, x)
        !! Sets a factor used to establish the simplification tolerance.
        class(scatter_plot_data), intent(inout) :: this
            !! The scatter_plot_data object.
        real(real64), intent(in) :: x
            !! The scaling factor.
        this%m_simplifyFactor = x
    end subroutine

! ------------------------------------------------------------------------------
    pure function spd_get_data_dependent_colors(this) result(rst)
        !! Gets a value determing if data-dependent colors should be used.
        class(scatter_plot_data), intent(in) :: this
            !! The scatter_plot_data object.
        logical :: rst
            !! True if data-dependent colors should be used; else, false.
        rst = this%m_dataDependentColors
    end function

! --------------------
    subroutine spd_set_data_dependent_colors(this, x)
        !! Sets a value determing if data-dependent colors should be used.
        class(scatter_plot_data), intent(inout) :: this
            !! The scatter_plot_data object.
        logical, intent(in) :: x
            !! True if data-dependent colors should be used; else, false.
        this%m_dataDependentColors = x
    end subroutine

! ******************************************************************************
! ADDED: JUNE 28, 2021 - JAC
! ------------------------------------------------------------------------------
    pure function spd_get_filled(this) result(rst)
        !! Gets a logical value determining if a filled curve should be drawn.
        class(scatter_plot_data), intent(in) :: this
            !! The scatter_plot_data object.
        logical :: rst
            !! True if the curve should be filled; else, false.
        rst = this%m_filledCurve
    end function

! --------------------
    subroutine spd_set_filled(this, x)
        !! Sets a logical value determining if a filled curve should be drawn.
        class(scatter_plot_data), intent(inout) :: this
            !! The scatter_plot_data object.
        logical, intent(in) :: x
            !! True if the curve should be filled; else, false.
        this%m_filledCurve = x
    end subroutine

! ******************************************************************************
! ADDED: JAN 12, 2024 - JAC
! ------------------------------------------------------------------------------
    pure function spd_get_use_var_point_size(this) result(rst)
        !! Gets a logical value determining if variable sized data points
        !! should be used.  The default is false, such that points will be of
        !! a constant size.
        class(scatter_plot_data), intent(in) :: this
            !! The scatter_plot_data object.
        logical :: rst
            !! True if variable size points should be used; else, false.
        rst = this%m_useVariableSizePoints
    end function

! --------------------
    subroutine spd_set_use_var_point_size(this, x)
        !! Sets a logical value determining if variable sized data points
        !! should be used.  The default is false, such that points will be of
        !! a constant size.
        class(scatter_plot_data), intent(inout) :: this
            !! The scatter_plot_data object.
        logical, intent(in) :: x
            !! True if variable size points should be used; else, false.
        this%m_useVariableSizePoints = x
    end subroutine

! ------------------------------------------------------------------------------
end module