Sources

SomeGraphs.Sources — Module

Provide convenient API for setting up graph's data. The core concept is that we can break the graph definition to parts w/ uniform structure, so that writing a data source to fill this structure allows using it to fill whatever data we want

  • X coordinates, Y coordinates, colors, bar sizes, etc.

We have a few kinds of these uniform structures. Each is built from two parts - one for all the data fields and one for all the configuration fields. All these fields are direct references to the graph fields, so they can be set via this view into the graph.

Some fields are shared between several views. For example, hovers for points in scatter graphs can be given by the X data, the Y data, or the color data. To support this we provide functions for adding hovers into the common (shared) field instead of simply overwriting it.

Some views are of one entry of a vector of structures (a series of bars, a line, a distribution, an annotation). Such an entry is appended by add_series! and its siblings, which return the index the view accessors take.

SomeGraphs.Sources.AbstractFields — Type

Abstract interface for a full data source consisting of data and a configuration fields. The concrete types of each depend on the specific graph role. These are views into the graph fields, bundled together to allow a function to easily set them in a uniform way regardless of the specific rule they play in the graph.

SomeGraphs.Sources.AbstractConfigurationFields — Type

Abstract interface for the configuration half of AbstractFields . Every concrete type says how the values are mapped to the range they are shown in, and most have additional fields as appropriate for the specific configuration. A role drawn along an axis has an axis::AxisConfiguration ; a role shown as colors or sizes is not drawn along an axis, so it has a scale::ScaleConfiguration (and the colors or sizes configuration it is the scale of).

Vectors

Types

SomeGraphs.Sources.VectorFields — Type
struct VectorFields{Configuration} <: AbstractFields
    data::VectorDataFields
    configuration::Configuration
end

AxisVectorFields = VectorFields{AxisConfigurationFields}
ColorsVectorFields = VectorFields{ColorsConfigurationFields}
SizesVectorFields = VectorFields{SizesConfigurationFields}

A data source view of one role of a graph whose entities are a vector: the data (a VectorDataFields ) and the configuration (an AxisConfigurationFields , ColorsConfigurationFields or SizesConfigurationFields ). A function writing into such a view fills the role from some source of data, and works the same on the X coordinates of points, the values of bars, the colors of either, and so on. The views are AxisVectorFields for values shown along an axis, ColorsVectorFields for values shown as colors (see ColorsConfigurationFields ) and SizesVectorFields for values shown as sizes (see SizesConfigurationFields ). They are obtained from a graph by the accessor functions ( x_axis_vector_fields , colors_vector_fields , ...), whose names follow the path of the values in the data of the graph.

SomeGraphs.Sources.VectorDataFields — Type
struct VectorDataFields
    values::VectorValuesData
    entities::VectorEntitiesData
end

The data half of a data source view (see VectorFields ): the VectorValuesData of one role of a graph (the X coordinates of its points, their colors, ...) and the VectorEntitiesData of the entities these values belong to. Both are the graph's own objects, so writing into them changes the graph. Several roles of the same entities (say, the X, Y, colors and sizes of points) share one entities , so hovers added through any of them are seen by all.

A source which only writes values, a title and hovers takes a VectorDataFields . The data half of every VectorFields is one, and so is a view of a role that has no configuration to speak of (the names of the bars, the groups of the rows of a heatmap), so such a source applies to all of them alike.

SomeGraphs.Sources.ColorsConfigurationFields — Type
struct ColorsConfigurationFields <: AbstractConfigurationFields
    scale::ScaleConfiguration
    colors::ColorsConfiguration
end

The configuration half of a ColorsVectorFields data source view (see VectorFields ): the ColorsConfiguration the values are colored by, and its scale . Colors are not drawn along an axis, so there are no ticks here; the title of the values takes precedence over the title of the colors configuration.

SomeGraphs.Sources.SizesConfigurationFields — Type
struct SizesConfigurationFields <: AbstractConfigurationFields
    scale::ScaleConfiguration
    sizes::SizesConfiguration
end

The configuration half of a SizesVectorFields data source view (see VectorFields ): the SizesConfiguration the values are sized by, and its scale . Sizes are not drawn along an axis, so there are no ticks here; the title of the values takes precedence over the title of the sizes configuration.

Accessors

Vector Data Fields

Axis Vector Fields

Colors Vector Fields

SomeGraphs.Sources.annotations_colors_vector_fields — Function
annotations_colors_vector_fields(graph, index::Integer)::ColorsVectorFields

The data source view of one annotation of a graph, given the index of the annotation. The annotation shares the entities of the axis it annotates (the bars).

SomeGraphs.Sources.rows_annotations_colors_vector_fields — Function
rows_annotations_colors_vector_fields(graph, index::Integer)::ColorsVectorFields

The data source view of one annotation of the rows of a graph, given the index of the annotation. The annotation shares the entities of the rows.

SomeGraphs.Sources.columns_annotations_colors_vector_fields — Function
columns_annotations_colors_vector_fields(graph, index::Integer)::ColorsVectorFields

The data source view of one annotation of the columns of a graph, given the index of the annotation. The annotation shares the entities of the columns.

Sizes Vector Fields

Entities

The entities are shared by all the roles of the same thing, so writing them through any role is seen by all. Reach them directly to add a hover line, or to hide entities with a mask, without filling any role.

SomeGraphs.Sources.points_entities — Function
points_entities(graph)::VectorEntitiesData

The entities of the points of a graph, shared by all their roles. Use this to add a hover line, or to hide points with a mask, without filling any role. For one line of a multi-line graph, use the entities of its PartFields .

SomeGraphs.Sources.bars_entities — Function
bars_entities(graph)::VectorEntitiesData

The entities of the bars of a graph, shared by all their roles. In a multiple series graph these are the bars shared by all the series; for the bars of one series, use the entities of its PartFields .

SomeGraphs.Sources.rows_arrangement — Function
rows_arrangement(graph)::ArrangementData

The arrangement of the rows of a graph (of a heatmap): the tree, groups and matrix they are arranged by.

SomeGraphs.Sources.columns_arrangement — Function
columns_arrangement(graph)::ArrangementData

The arrangement of the columns of a graph (of a heatmap): the tree, groups and matrix they are arranged by.

Sides

A side of a heatmap stands for its data, configuration and placement together, for copying one side onto another.

SomeGraphs.Sources.HeatmapSide — Type
struct HeatmapSide
    graph::HeatmapGraph
    is_rows::Bool
end

One side (the rows or the columns) of a heatmap graph, as returned by rows_side and columns_side . It stands for the three things a side has: its data ( side_data ), its configuration ( side_configuration ) and its computed placement ( side_placement ).

As a sink, it reaches the entities and the arrangement of the side. It doesn't reach the annotations. Each annotation is a role of its own, reached through its own view (e.g. rows_annotations_colors_vector_fields ), so a source given the side doesn't write into all of them. As a source, it is what the fills copying one side onto another take.

SomeGraphs.Sources.side_data — Function
side_data(side::HeatmapSide)::HeatmapSideData

The data of a side of a heatmap: the entities, the arrangement and the annotations of its entries.

SomeGraphs.Sources.side_placement — Function
side_placement(side::HeatmapSide)::SidePlacement

The computed placement of a side of a heatmap: the final order of its entries, and the tree they were placed by, if one was needed. Computing it once (see heatmap_placement ) serves both sides.

Matrices

Types

SomeGraphs.Sources.MatrixFields — Type
struct MatrixFields <: AbstractFields
    data::MatrixDataFields
    configuration::MatrixConfigurationFields
end

The data source view of the entries of a graph whose entities are arranged in rows and columns (the entries of a heatmap), shown as colors.

SomeGraphs.Sources.MatrixDataFields — Type
struct MatrixDataFields
    values::MatrixValuesData
    entities::MatrixEntitiesData
    rows_entities::VectorEntitiesData
    columns_entities::VectorEntitiesData
end

The data half of a MatrixFields data source view: the MatrixValuesData of the entries of a graph (a heatmap), the MatrixEntitiesData of its cells, and the VectorEntitiesData of each of its two axes. All are the graph's own objects, so writing into them changes the graph.

A matrix source knows the two axes its data is indexed by, so it can fill what belongs to them: the names of the rows and of the columns, shown as their tick labels, and a hover per row and per column on top of the hover of each cell. The axis entities are the same ones the row and column views hand out ( rows_annotations_colors_vector_fields , ...), so whatever is written through either path is seen by both.

Accessors

Parts

Types

SomeGraphs.Sources.PartFields — Type
struct PartFields{GraphType, PartType <: AbstractPartData}
    graph::GraphType
    index::Int
    data::PartType
end

The data source view of one part of a graph built from several such parts (a series of bars, a line, a distribution). This allows a data source to set the part regardless of the role it plays in the graph. Since parts may have multiple instances, they are identified by their index in the graph . Parts are different from simple vector data in that they have scalar properties (e.g., name, hover) and may contain multiple vector data (e.g., both x and y coordinates for a line part). The part data acts as a view that allows accessing the relevant fields depending on the PartType .

A part is not a sink, since it may play several roles (a line has an x and a y ). A data source is given one of its roles (e.g. part.x ) or its entities instead.

Creators

SomeGraphs.Sources.add_series! — Function
add_series!(graph, [series::SeriesData = SeriesData()])::PartFields

Append a series to a graph (of series of bars) and return its view (see PartFields ). Whatever the series leaves at its defaults can be set later, through the view or directly.

SomeGraphs.Sources.add_line! — Function
add_line!(graph, [line::LineData = LineData()])::PartFields

Append a line to a graph (of lines) and return its view (see PartFields ). Whatever the line leaves at its defaults can be set later, through the view or directly.

SomeGraphs.Sources.add_distribution! — Function
add_distribution!(graph, [distribution::DistributionData = DistributionData()])::PartFields

Append a distribution to a graph (of distributions) and return its view (see PartFields ). Whatever the distribution leaves at its defaults can be set later, through the view or directly.

SomeGraphs.Sources.add_annotation! — Function
add_annotation!(graph, [annotation::AnnotationData = AnnotationData()])::Int

Append an annotation to the entities of a graph (the bars) and return its index (for annotations_colors_vector_fields ). Whatever the annotation leaves at its defaults can be set later, through the view.

SomeGraphs.Sources.add_rows_annotation! — Function
add_rows_annotation!(graph, [annotation::AnnotationData = AnnotationData()])::Int

Append an annotation to the rows of a graph and return its index (for rows_annotations_colors_vector_fields ). Whatever the annotation leaves at its defaults can be set later, through the view.

SomeGraphs.Sources.add_columns_annotation! — Function
add_columns_annotation!(graph, [annotation::AnnotationData = AnnotationData()])::Int

Append an annotation to the columns of a graph and return its index (for columns_annotations_colors_vector_fields ). Whatever the annotation leaves at its defaults can be set later, through the view.

Accessors

Sinks

A data source doesn't need to know which view it is filling, or how many. It takes Sinks and walks them with visit_data_sinks or visit_configuration_sinks , writing a method per leaf it fills and an explicit no-op for the leaves it ignores.

SomeGraphs.Sources.VectorDataLeaf — Type

A struct holding graph data with a value per entity: the values of a role, the entities they belong to, or the arrangement of the entities of a heatmap axis.

SomeGraphs.Sources.Sinks — Type

What a data source accepts: one AnySink , or a tuple or vector of them. Passing several lets one set of data feed several places in the graph. A data source writes only the sinks which hold the half it fills and ignores the rest, so a mixed collection is fine and either half may match nothing at all.

The method of a data source which walks the sinks takes every Sinks but the leaves it writes: Union{AnyContainer, ConfigurationLeaf, Tuple, AbstractVector} when writing data, and the mirror when writing configuration. It has a method per leaf it writes, and one explicit no-op method for the leaves it ignores, so a leaf it says nothing about is a MethodError . A data source writing data has one more method, for the leaves of the other shape (a matrix leaf for a source of a value per entity, and a vector leaf for a source of a value per matrix entry). It raises an ArgumentError , since such a sink has no place for the data. Taking Sinks in the walking method would match a leaf too, and walking it calls the same method again, forever.

SomeGraphs.Sources.visit_data_sinks — Function
visit_data_sinks(visitor::Function, sinks::Sinks)::Nothing

Call the visitor on each data struct the sinks reach (see visit_graph_parts ). This lets a data source write a method per struct it fills, without a traversal of its own. It isn't called on the views themselves.

A struct is visited once however many sinks reach it. All the roles of an axis share its entities, and add_hovers! appends, so without this a hover would be added once per sink which reaches the same entities.

A matrix is walked into its entries only. Its row and column entities belong to their axes and are sized by one axis each, so a value per matrix entry can't be written to them; they are reached by naming them directly.

SomeGraphs.Sources.matrix_sink_error — Function
matrix_sink_error(leaf::MatrixDataLeaf)::ArgumentError

The error of giving a matrix sink to a data source which puts a value per entity. The entries and cells of a matrix have no such value. Such a data source raises it for the matrix leaf (see Sinks ).

SomeGraphs.Sources.vector_sink_error — Function
vector_sink_error(leaf::VectorDataLeaf)::ArgumentError

The error of giving a vector sink to a data source which puts a value per entry of a matrix. A vector has no such value. Such a data source raises it for the vector leaf (see Sinks ).

Every walk goes through visit_graph_parts , which calls its visitor on every struct of a graph or of some sinks. Use it directly to change a whole graph (e.g. to hide all its legends). The two sink visitors above are its use by data sources. Each struct which a graph or a view holds has a method of it. A new struct needs one too.

SomeGraphs.Common.visit_graph_parts — Function
visit_graph_parts(visitor::Function, part::Any, visited::Base.IdSet)::Nothing

Call the visitor on a part of a Graph (or on the whole graph), and on every struct it holds, once each. The walk doesn't go into a leaf: the struct of a role, such as an AxisConfiguration or a VectorValuesData , which a visitor handles whole (e.g. together with its scale).

Each struct of this package which a graph or a view may hold has a method of its own, defined right after it. A leaf's method calls visit_graph_leaf . Any other struct's method calls visit_graph_fields , which also walks its fields, so a new field is walked without further code. There is no fallback, so a walk which reaches a struct without a method is an error.

SomeGraphs.Common.visit_graph_fields — Function
visit_graph_fields(visitor::Function, container::Any, visited::Base.IdSet)::Nothing

Call the visitor on the container , then walk the parts held in its fields (see visit_graph_parts ): each field holding a struct of this package, or a vector of them. Any other field (a number, a string, an enum, a vector of numbers, ...) holds no parts.

Puts

Generic data sources, putting data a caller already has into any sinks. A specific data source fetches its data and hands it to these, then says how to show it.

SomeGraphs.Sources.put_vector_data! — Function
put_vector_data!(
    sinks::VectorDataSinks,
    value_per_entry::Union{AbstractVector{<:Real}, AbstractVector{<:AbstractString}};
    title::Maybe{AbstractString} = nothing,
    hover_format::Maybe{Function} = nothing,
)::Nothing

Put a value_per_entry into the sinks : as the values of a role, and as a hover line on the entities.

The title prefixes the hover line, as title: value . The hover_format (if any) turns each value into its text in the hover line (e.g. percent_format ). It doesn't change the values of the role. Nothing is configured here, because how to show a value depends on what it is; a specific data source says that in its own configuration put. That put should match the hover_format (e.g., a percent axis and a percent hover).

SomeGraphs.Sources.put_vector_names_data! — Function
put_vector_names_data!(sinks::VectorDataSinks, name_per_entry::AbstractVector{<:AbstractString})::Nothing

Name the entities of the sinks after the name_per_entry . Where the graph has room to label the entities, these become their tick labels. They are also the first line of the hover of each entity.

SomeGraphs.Sources.put_vector_mask_data! — Function
put_vector_mask_data!(
    sinks::VectorDataSinks,
    is_shown_per_entry::Union{AbstractVector{Bool}, BitVector},
)::Nothing

Hide the entities of the sinks which are not shown by the is_shown_per_entry mask. Hidden entities are still part of the data, so they take part in whatever is computed from it, unless the relevant configuration says otherwise.

SomeGraphs.Sources.put_vector_order_data! — Function
put_vector_order_data!(
    sinks::VectorDataSinks,
    order::AbstractVector{<:Integer},
)::Nothing

Give the entities of the sinks the order (a permutation of their indices). What the order means depends on the graph; for a heatmap side, see HeatmapSideConfiguration .

SomeGraphs.Sources.put_matrix_data! — Function
put_matrix_data!(
    sinks::MatrixDataSinks,
    value_per_row_per_column::AbstractMatrix{<:Real};
    title::Maybe{AbstractString} = nothing,
    hover_format::Maybe{Function} = nothing,
)::Nothing

Put a value_per_row_per_column into the sinks : as the values of the entries, and as a hover line on each entry. The matrix twin of put_vector_data! , including the hover_format .

The row and the column entities are not written here. They belong to their sides and are sized by one side each, so they are named separately; see put_matrix_names_data! .

SomeGraphs.Sources.put_matrix_names_data! — Function
put_matrix_names_data!(
    sinks::MatrixDataSinks,
    name_per_row::AbstractVector{<:AbstractString},
    name_per_column::AbstractVector{<:AbstractString},
)::Nothing

Name the rows and the columns of the sinks after the name_per_row and the name_per_column . The matrix twin of put_vector_names_data! .

The two sides are named together here rather than through visit_data_sinks , which doesn't walk into them because they are sized by one side each while the entries are sized by both. A vector sink has no rows or columns to name, so it is an error here.

Gets

Reading back the names the sinks already hold, so a data source can fill entities which were named before, without being told again which entries they are.

SomeGraphs.Sources.get_vector_names_data — Function
get_vector_names_data(sinks::VectorDataSinks)::Maybe{AbstractVector{<:AbstractString}}

The names of the entities of the sinks , as given by put_vector_names_data! , or nothing if they have none. This lets a data source fill the entities which were already named, without being told again which entries they are.

Entities with no names don't count. If the sinks reach several entities with different names, this is an error.

Copying Sides

A side of a heatmap is a data source too, for laying out another heatmap the same way. Each of these copies one part of a side, so the two graphs stay independent afterwards. All but the placement are plain copies of inputs; the placement is computed, so copying it is special (see fill_placement! ).

SomeGraphs.Sources.fill_side! — Function
fill_side!(target::HeatmapSide, source::HeatmapSide)::Nothing

Fill the target side with a copy of everything about the source side: its entities, arrangement, annotations and configuration, then its computed placement. This lays out the target exactly as the source , even when the data of the two graphs differ.

The placement comes last because fill_placement! is not a plain copy. It turns the computed placement of the source into inputs of the target , and clears the copied inputs which then have no effect.

SomeGraphs.Sources.fill_entities! — Function
fill_entities!(sinks::VectorDataSinks, source::Union{HeatmapSide, VectorEntitiesData})::Nothing

Fill the entities of the sinks with a copy of the names, hovers, mask and order of the entities of the source .

SomeGraphs.Sources.fill_arrangement! — Function
fill_arrangement!(sinks::VectorDataSinks, source::Union{HeatmapSide, ArrangementData})::Nothing

Fill the arrangement of the sinks (that is, of the sides of a heatmap among them) with the tree, and a copy of the groups, subgroups and arrange_by matrix, of the arrangement of the source .

SomeGraphs.Sources.fill_annotations! — Function
fill_annotations!(target::HeatmapSide, source::HeatmapSide)::Nothing

Fill the annotations of the target side with a copy of the annotations of the source side, and of the order they are shown in.

SomeGraphs.Sources.fill_configuration! — Function
fill_configuration!(target::HeatmapSide, source::HeatmapSide)::Nothing

Fill the configuration of the target side with a copy of the configuration of the source side.

SomeGraphs.Sources.fill_placement! — Function
fill_placement!(target::HeatmapSide, source::Union{HeatmapSide, SidePlacement})::Nothing

Fill the target side with the computed placement of the source : its final order into the order of the entities, and its tree (if any) into the hclust of the arrangement. The target is then placed exactly as the source was, without clustering or slanting anything.

Unlike the other fills, this does not copy an input of the graph. It copies what the inputs of the source computed, and turns it into inputs of the target . The inputs of the target which computed its own placement then have no effect, and giving an input with no effect is an error (see HeatmapSideConfiguration ). So this also clears them:

  • The tree_source , order_source , linkage and metric of the configuration of the target . The sources are inferred from the given order and tree instead.
  • The arrange_by matrix of the arrangement of the target , which nothing is clustered by.
  • The groups of the arrangement of the target if its configuration has no groups_gap , and likewise the subgroups if it has no subgroups_gap . Groups which are drawn as gaps are kept.

Since what is cleared depends on the configuration of the target , fill it first when filling both (as fill_side! does).

Example:

Show a second heatmap of other values with the rows laid out, grouped and annotated as in the first:

fill_side!(rows_side(other), rows_side(graph))

Hovers

SomeGraphs.Sources.add_hovers! — Function
add_hovers!(
    entities::Union{VectorEntitiesData, MatrixEntitiesData},
    hovers::AbstractArray{<:AbstractString};
    [title::Maybe{AbstractString} = nothing]
)::Nothing

Add a line to the hover of each of the entities : the hovers entry of the entity (a vector for VectorEntitiesData , a matrix for MatrixEntitiesData ), prefixed by the title (if any) as title: hover . The lines of several calls are joined by <br> , in the order of the calls. All the hovers given to the same entities must be of the same size.

Hover Formats

A hover line shows a value as text. By default this is the value as Julia prints it. A hover_format given to a put (see put_vector_data! ) shows it differently, e.g. as a percent to match a percent axis.

SomeGraphs.Sources.fixed_format — Function
fixed_format(; digits::Integer, separated::Bool = true)::Function

A hover_format (see put_vector_data! ) showing each value with a fixed number of digits after the decimal point (e.g., 0.01 for 0.012345 with 2 digits).

If separated , the digits are grouped by 3, with a narrow no-break space, on both sides of the decimal point (e.g., 12 345.678 9 , or 0.000 123 ). This is a no-op for short numbers. The same holds for the other formats.

SomeGraphs.Sources.significant_format — Function
significant_format(; sigdigits::Integer, separated::Bool = true)::Function

A hover_format (see put_vector_data! ) showing each value as printf 's %g does, with sigdigits significant digits (e.g., 0.0123 for 0.012345 with 3 digits). Trailing zeros are dropped (e.g., 25 for 25.0 ). A value is shown in scientific notation when its exponent is at least sigdigits or below -4 (e.g., 1.23e+03 for 1234 with 3 digits). The digits are separated as in fixed_format .

SomeGraphs.Sources.scientific_format — Function
scientific_format(; digits::Integer, separated::Bool = true)::Function

A hover_format (see put_vector_data! ) showing each value in scientific notation, with digits digits after the decimal point (e.g., 1.23e-02 for 0.012345 with 2 digits). The digits of the mantissa are separated as in fixed_format ; those of the exponent never are.

SomeGraphs.Sources.percent_format — Function
percent_format(; digits::Integer, separated::Bool = true)::Function

A hover_format (see put_vector_data! ) showing each value (a fraction) as a percent, with a fixed number of digits after the decimal point (e.g., 25.0% for 0.25 with 1 digit). This matches an axis whose scale.percent is set. The digits are separated as in fixed_format .

Example:

One source function, writing a vector of values as the values of a role and as a hover line. It says what to do with a VectorValuesData and with a VectorEntitiesData , and visit_data_sinks finds them in whatever it is given. Given a matrix struct, it fails rather than silently doing nothing, since it says nothing about those:

using SomeGraphs

function source!(
    sinks::Union{AnyContainer, ConfigurationLeaf, Tuple, AbstractVector},
    values::AbstractVector{<:Real},
    title::AbstractString,
)::Nothing
    visit_data_sinks(sinks) do sink
        return source!(sink, values, title)
    end
    return nothing
end

function source!(values_data::VectorValuesData, values::AbstractVector{<:Real}, title::AbstractString)::Nothing
    values_data.vector = values
    values_data.title = title
    return nothing
end

function source!(entities::VectorEntitiesData, values::AbstractVector{<:Real}, title::AbstractString)::Nothing
    add_hovers!(entities, string.(values); title)
    return nothing
end

graph = points_graph()
source!(x_axis_vector_fields(graph), collect(0:10) .* 10, "X")
source!(y_axis_vector_fields(graph), collect(0:10) .^ 2, "Y")
source!(points_colors_vector_fields(graph), collect(0:10), "Color")
using PlotlyDocumenter
to_documenter(graph.fig)

All three roles share the points' entities, so each call adds one hover line to the same entities, and the points end up with three. Had they been passed together in one call, visit_data_sinks would have visited those entities once, and the hover would have been added once.

Index