Skip to content

DataExtension API Graphs

Aurora Lahtela edited this page Oct 17, 2026 · 5 revisions

Plan Header

DataExtension API - Graphs

DataExtension Graph APIs require DATA_EXTENSION_GRAPH_API capability.


📈 @GraphProvider annotation

Speciality: Allows you to add sampled or historical data that's drawn as a line-graph.

All graphs are append only, e.g. once value has been given it will not be possible to delete via the API.

Javadocs

Example use cases:

Usage:

@GraphProvider(
        displayName = "Balance over time", // Always required
        sampleInterval = 1, sampleIntervalUnit = TimeUnit.MINUTES,
        priority = 0,
        iconName = "chart-line",
        iconFamily = Family.SOLID,
        iconColor = Color.GREEN,
        xAxisType = XAxisType.DATE_MILLIS,
        xAxisSoftMin = 0, // Disabled if not given
        xAxisSoftMax = 2, // Disabled if not given
        yAxisSoftMin = 0,
        yAxisSoftMax = 2,
        supportsStacking = false,
        strategy = HistoryStrategy.NO_HISTORY,
        supportedAggregateFunctions = {MAX_PEAK, MAX_PEAK_OVER_TIME}
)
public PlayerGraphDataSource playerBalanceOverTime() {
    return new PlayerGraphDataSource() {
        @Override
        public Optional<DataPoint> getPoint(long currentTimestamp, UUID playerUUID, String playerName) {
            return Optional.of(new DataPoint(currentTimestamp, List.of(1.0)));
        }

        @Override // This method is called during registration and if DataPoint list increases length
        public List<SeriesMetadata> getSeriesMetadata() {
            return List.of(new SeriesMetadata(eco.currencyNamePlural(), "$", GraphFormatType.NONE, GraphColors.GREEN));
        }

        @Override // This method is not called (or required) with HistoryStrategy.NO_HISTORY
        public List<DataPoint> getPointHistory(long currentTimestamp, UUID playerUUID, String playerName) {
            return List.of();
        }
    };
}
@GraphProvider(...)
public ServerGraphDataSource serverGraph() {
    return new ServerGraphDataSource() {
        @Override
        public Optional<DataPoint> getPoint(long currentTimestamp) {
            return Optional.of(new DataPoint(currentTimestamp, List.of(1.0)));
        }

        @Override
        public List<SeriesMetadata> getSeriesMetadata() {
            return List.of(new SeriesMetadata("Example", "cm", GraphFormatType.NONE, GraphColors.GREEN));
        }

        @Override
        public List<DataPoint> getPointHistory(long currentTimestamp) {
            return List.of();
        }
    };
}

Concept: Series

GraphProvider allows displaying line graph data. Each line on the graph (there can be multiple) is considered a series. Each series has its own SeriesMetadata to differentiate it from the other lines.

It is important that once you define a series, it stays on the same index at all times. Series metadata at index 0 is associated with values at index 0. In the usage example the SeriesMetadata "Example" is associated with the value 1.0.

Sample frequency

It is important to consider how many points your GraphProvider will feed to the database, so that it doesn't overwhelm disk space of servers. This is controlled using GraphProvider sampleInterval and sampleIntervalUnit parameters.

PlayerGraphDataSource minimum sample interval is 30 seconds and any values lower than that are set to 30 seconds.
ServerGraphDataSource minimum sample interval is 5 seconds and any values lower than that are set to 5 seconds.

Good aim for storage is 1GB in 30 days or longer.

Points per hour is calculated with 60 minutes / sample rate, e.g. 30 second sample rate is 3600/30 = 120 points per hour. With 100 players that is 12000 points per hour.

Storage requirements can be calculated with (points per hour) * (players) * 64 * (2 + y)

  • where y is amount of values returned with DataPoint.
  • y=1: 120 * 100 * 64 * (2 + 1) = 2.3 MB of data/hour = 17.3 days to fill up 1 GB.

Returning nothing

If your data has not changed it is possible to return Optional.empty() and a new point will not be added.

Player graph speciality: sampling on player leave

If your DataExtension supports CallEvent.PLAYER_LEAVE, Plan will try to sample the graph one last time on Player leave.

X axis

x axis is defined by constants in the annotation

xAxisType = XAxisType.DATE_MILLIS,
xAxisSoftMin = 0, // Disabled if not given
xAxisSoftMax = 2, // Disabled if not given

Supported x axis types are:

  • VALUE - Displays X as a number
  • DATE_MILLIS (default) - Displays X as a date
  • TIME_AMOUNT_MILLIS - Displays X as a time amount (like playtime)

It is not recommended to set xAxisSoftMin or xAxisSoftMax unless you're using VALUE or TIME_AMOUNT_MILLIS as axis.

Plan will sort all given data with x asceding even if it is given out of order.

Y axis

y axis is defined by SeriesMetadata as well as yAxisSoftMin, yAxisSoftMax in the annotation.

Every series can have its own Y-axis (but they can also share them)

Y-axis is defined by SeriesMetadata unitLabel (2nd parameter) and formatType (3rd parameter)

Supported formatTypes are

  • NONE (Default) - no formatting, just a double/int.
  • TIME_AMOUNT - Milliseconds of time, formatted same as Playtime.
  • MILLISECONDS - Milliseconds of time, formatted same as Ping.
  • PERCENTAGE - values between 0.0 and 1.0.
  • BYTES - formatted same as RAM/Disk space: 1000 = 1 kB, 1000000 = 1 MB, etc.
  • INTEGER - any decimals are cut off.

Line colors

SeriesMetadata allows defining line color as HEX #000000-#ffffff or #00000000-#ffffffff (alpha value), or by using GraphColors.

GraphColors.RED will show the line same as any other plugin color (e.g. Color.RED on an iconColor)

Nulls in SeriesMetadata

You can give nulls in any parameter to SeriesMetadata constructor new SeriesMetadata(null, null, null, null), but Plan will apply default behavior to missing metadata.

  • Series name (1st parameter) - Will use series #n as series label
  • Unit label (2nd) - Will use "" as unit (no unit)
  • GraphFormatType (3rd) - Will use GraphFormatType.NONE
  • hexColor (4th) - Will use predetermined series of graph colors cycling through 16 plugin colors starting from LIGHT_BLUE

Point history

ServerGraphDataSource and PlayerGraphDataSource allow overriding getPointHistory method. Same concept of "Series are at index" applies here.

This method allows you to send new values to point history.

GraphProvider parameter strategy takes a HistoryStrategy which determines how the points from this method will be added.

HistoryStrategy values are:

  • NO_HISTORY (default) - Function will not be called
  • REPLACE_CHANGED_VALUES - Any values with same x value as existing will be replaced with new values, new ones appended
  • ONLY_APPEND_MISSING - Any values with existing x value in the database will be ignored, new ones appended

This means that you can send any data that Plan might not have received while plugins were offline.

It is recommended that you only send new data if at all possible, to reduce the memory footprint of calling your method.

Clone this wiki locally