Repository navigation
DataExtension API Graphs

DataExtension Graph APIs require DATA_EXTENSION_GRAPH_API capability.
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();
}
};
}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.
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.
If your data has not changed it is possible to return Optional.empty() and a new point will not be added.
If your DataExtension supports CallEvent.PLAYER_LEAVE, Plan will try to sample the graph one last time on Player leave.
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 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.
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)
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 #nas 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
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.