Docs

Documentation versions (currently viewingVaadin 25.3 (pre-release))

AI-Powered Chart

Use ChartAIController to let users build and update Highcharts visualizations from the application database using natural language.

ChartAIController creates and updates a Chart (Vaadin’s interactive charting component) visualization based on natural-language requests. Backed by a DatabaseProvider, the controller lets the LLM inspect the database schema, write SQL queries for one or more series, and update the Highcharts configuration independently of the data.

Note
Commercial Feature

A commercial Vaadin subscription is required to use AI-Powered Chart in your project.

Data and configuration are kept separate: series data comes from SQL queries, while visual appearance comes from the configuration. Both updates are applied together at the end of the LLM turn, so the user never sees a half-updated chart.

Basic Usage

Create a Chart, construct a controller, and wire it to the orchestrator:

Source code
Java
Chart chart = new Chart();
MessageInput messageInput = new MessageInput();

DatabaseProvider databaseProvider = new JdbcDatabaseProvider(dataSource);
ChartAIController controller = new ChartAIController(chart, databaseProvider);

AIOrchestrator.builder(provider, systemPrompt)
        .withInput(messageInput)
        .withController(controller)
        .build();

add(messageInput, chart);

Example prompts:

  • "Plot monthly revenue for the last year as a column chart."

  • "Show revenue by region as a pie chart."

  • "Compare 2025 and 2026 quarterly sales side-by-side with a legend."

  • "Turn this into an area chart and add a 'Revenue (USD)' y-axis title."

Tip
Built-In Workflow Instructions
The controller already informs the LLM of the workflow it needs. You can focus your own system prompt on application-specific behavior.
Note
Provider Compatibility
ChartAIController does not support OpenAI’s strict tool-calling mode. Strict mode is off by default in both LangChain4j and Spring AI; only users who explicitly opt in are affected.

Persisting Chart State

ChartState captures both the SQL queries and the Highcharts configuration. Register a state change listener to persist the state automatically after each successful AI request:

Source code
Java
controller.addStateChangeListener(state ->
        sessionStore.save(sessionId, state));

// Restore on a new session
ChartState saved = sessionStore.load(sessionId);
if (saved != null) {
    controller.restoreState(saved);
}

sessionStore here is a placeholder for your own storage — a database table, a file, a VaadinSession attribute, or whatever fits your application.

Listeners do not fire when restoreState() is called. The current state is also automatically included in session serialization, so no extra save/restore code is needed for in-session persistence.

Reconnecting after Deserialization

ChartAIController is not serializable. After session restore, create a new controller, pass it to reconnect() together with the new provider, and optionally re-apply the saved state:

Source code
Java
ChartAIController controller = new ChartAIController(chart, databaseProvider);
orchestrator.reconnect(provider)
        .withController(controller)
        .apply();

Custom Data Conversion

DefaultDataConverter maps SQL result rows to Highcharts series automatically. To take full control — for example, to post-process rows, merge data from multiple queries into a single series, or apply custom formatting — implement DataConverter and register it with setDataConverter():

Source code
Java
public class CurrencyDataConverter implements DataConverter {

    @Override
    public List<Series> convertToSeries(List<Map<String, Object>> data) {
        DataSeries series = new DataSeries();
        for (Map<String, Object> row : data) {
            String name = (String) row.get("category");
            Number value = (Number) row.get("value");
            series.add(new DataSeriesItem(name, roundToCents(value)));
        }
        return List.of(series);
    }
}

controller.setDataConverter(new CurrencyDataConverter());

The converter receives the raw rows from DatabaseProvider.executeQuery() and returns one or more Series instances.

Combining with Dashboard

ChartAIController manages a single chart, but you can combine several of them with the Dashboard component to build an AI-generated dashboard that users arrange themselves and whose layout and chart state can be saved across sessions. Each dashboard widget hosts its own Chart and ChartAIController instance; persist each controller’s state alongside the dashboard’s own layout state to let users return to the same chart set and layout in a later session.