Authoritative guide for AI-assisted work on this repository. Keep this file updated as new decisions are made.
XChart is a lightweight Java charting library (org.knowm.xchart).
Current version: 4.0.0-SNAPSHOT | Java target: 11 | Build: Maven ≥ 3.9.0
xchart/ ← core library (the only deliverable jar)
xchart-demo/ ← standalone demo app; references xchart as a dep
| Package | Purpose |
|---|---|
org.knowm.xchart |
Public API: chart types, series, builders |
org.knowm.xchart.internal.chartpart |
Rendering: Chart, Plot_*, PlotContent_*, Legend_*, Axis* |
org.knowm.xchart.internal.series |
Abstract series base classes |
org.knowm.xchart.internal.style |
SeriesColorMarkerLineStyle, cycler |
org.knowm.xchart.style |
Concrete stylers (PieStyler, CategoryStyler, …) |
org.knowm.xchart.style.theme |
Theme implementations |
org.knowm.xchart.style.colors |
Color utilities / FontColorDetector |
org.knowm.xchart.style.lines |
SeriesLines |
org.knowm.xchart.style.markers |
SeriesMarkers |
Every chart type Foo requires this exact set of classes:
| Role | Class name | Extends |
|---|---|---|
| Chart | FooChart |
Chart<FooStyler, FooSeries> |
| Builder | FooChartBuilder |
ChartBuilder<FooChartBuilder, FooChart> |
| Styler | FooStyler |
Styler or AxesChartStyler |
| Series | FooSeries |
appropriate series base (see below) |
| Plot | Plot_Foo<ST, S> |
Plot_<ST, S> |
| Plot content | PlotContent_Foo<ST, S> |
PlotContent_<ST, S> |
| Legend | Legend_Foo<ST, S> |
Legend_<ST, S> |
Render style enums live inside the series class (e.g. CategorySeries.CategorySeriesRenderStyle).
Series (abstract)
└─ AxesChartSeries (abstract) – has xMin/xMax/yMin/yMax, stroke, lineColor
├─ AxesChartSeriesNumericalNoErrorBars
└─ AxesChartSeriesCategory – adds xData, yData, errorBars
└─ CategorySeries, HeatMapSeries, …
└─ (direct) PieSeries, DialSeries, RadarSeries, …
Series.DataTypeenum:Number,Date,StringcalculateMinMax()must be called whenever series data changes
// 1. plain size
public FooChart(int width, int height) {
super(width, height, new FooStyler());
axisPair = new AxisPair<>(this); // omit for non-axes charts (Pie, Dial, Radar)
plot = new Plot_Foo<>(this);
legend = new Legend_Foo<>(this);
}
// 2. custom Theme instance
public FooChart(int width, int height, Theme theme) {
this(width, height);
styler.setTheme(theme);
}
// 3. ChartTheme enum
public FooChart(int width, int height, ChartTheme chartTheme) {
this(width, height, chartTheme.newInstance(chartTheme));
}
// 4. Builder (always delegates to #3)
public FooChart(FooChartBuilder chartBuilder) {
this(chartBuilder.width, chartBuilder.height, chartBuilder.chartTheme);
setTitle(chartBuilder.title);
// set axis titles etc. from builder fields
}// Field (private, initialized in setAllStyles())
private SomeType fieldName;
// Getter — blank line before return
public SomeType getFieldName() {
return fieldName;
}
// Setter — Javadoc with @param, fluent return this
/**
* One-sentence description.
*
* @param fieldName description
*/
public FooStyler setFieldName(SomeType fieldName) {
this.fieldName = fieldName;
return this;
}- All fields must be initialized in
setAllStyles(), pulling values fromthemewhere applicable. setAllStyles()must callsuper.setAllStyles()first.- Never add state to the base
Stylerclass unless it truly applies to every chart type.
- Formatter:
fmt-maven-plugin(google-java-format). - Check only:
mvn fmt:check(used in CI). Run this to detect violations. - NEVER run
mvn fmt:formatproject-wide. It reformats every file, pollutes diffs, and causes merge conflicts across all open branches. If a PR has violations, ask the contributor to runmvn fmt:formaton their own changed files only and push a fix commit. - Indentation: 2 spaces (google style).
- Imports: sorted by google-java-format; no wildcard imports in
src/main. Tests may useimport static … Assertions.*. - One blank line between class members; blank line before
returnin getters. - Always end files with a newline character.
# Full build + tests
mvn clean verify
# Format source
mvn fmt:format
# Tests only
mvn test -pl xchart
# Skip tests
mvn install -DskipTestsxchart-demo depends on xchart via the local Maven repository (not the source tree).
You must install xchart first, then run the demo:
mvn install -pl xchart -DskipTests && \
mvn compile exec:java \
-pl xchart-demo \
-Dexec.mainClass="org.knowm.xchart.standalone.issues.TestForIssueXXX"Using just exec:java without the install step will run with a stale jar and changes won't be visible.
Tests use JUnit Jupiter 5 + AssertJ.
@BeforeEach
void setUp() { chart = new FooChart(800, 600, GGPlot2); }
@Test
void descriptiveCamelCaseNameNoTestPrefix() {
assertAll(
() -> assertDoesNotThrow(...),
() -> assertThat(series.getName()).isEqualTo("expected")
);
}
// Exception testing
assertThatThrownBy(() -> { ... })
.isInstanceOf(IllegalArgumentException.class)
.hasMessageMatching("Series name >x< ...");- Tests go in
xchart/src/test/java/org/knowm/xchart/mirroring the main package. - One test class per chart type or internal component.
- New public API must include tests.
Changes in these files affect every chart type — review with extra care:
| File | Impact |
|---|---|
Chart.java |
Base of all charts |
Styler.java |
Base of all stylers |
Series.java |
Base of all series |
AxisPair.java |
All axes-based charts |
Axis.java |
All axes-based charts |
PlotContent_.java |
All PlotContent renderers |
Plot_.java |
All Plot wrappers |
Legend_.java |
All legends |
Utils.java |
Used across many renderers |
CSVImporter.java |
Public import API |
Any PR touching these files should be tested by painting multiple chart types, not just the one the PR targets.
Every code PR should be accompanied by a standalone runnable demo that exercises the fix or feature.
| PR type | Package | Naming |
|---|---|---|
| Fixes a numbered issue | xchart-demo/…/standalone/issues/ |
TestForIssueXXX.java (XXX = issue number) |
| New feature, no specific issue | xchart-demo/…/standalone/prs/ |
TestForPRXXX.java (XXX = PR number) |
package org.knowm.xchart.standalone.prs; // or .issues
public class TestForPRXXX {
public static void main(String[] args) {
new SwingWrapper<>(getChart()).displayChart();
}
/** Constructs and returns the chart without launching a window (headless-safe). */
public static FooChart getChart() {
// build and return chart
}
}getChart()must bepublic staticso it can be called from unit tests without a display.- No Swing/AWT calls outside of
main(). - Separate
getChartXxx()methods when demonstrating multiple variants of the same feature.
When evaluating a PR, rank it higher if it:
- Passes
mvn fmt:check(no formatting violations). - Follows the exact naming conventions above.
- Adds or updates tests for new/changed behaviour.
- Targets only the chart type it claims to change (no incidental changes to base classes).
- Is free of wildcard imports in
src/main. - Has a
\nat the end of every changed file. - Does not set sibling state as a side-effect of a setter (e.g. a setter for field A silently nulling field B is fragile).
- Uses the existing
seriesMap(LinkedHashMap — insertion order is meaningful) iteration patterns.
Lower-risk PRs: single-field styler additions, dependency bumps with passing CI.
Higher-risk PRs: new chart types, changes to rendering base classes, refactors of Utils/CSVImporter.
Last updated: 2026-05-17
| PR | Bump | Decision |
|---|---|---|
| #911 | javafx-controls 11 → 26-ea+13 | ⏳ pending |
| #901 | maven-javadoc-plugin 3.10 → 3.12 | ⏳ pending |
| #899 | maven-surefire-plugin 3.5.0 → 3.5.4 | ⏳ pending |
| #897 | pdfbox-graphics2d 3.0.2 → 3.0.5 | ⏳ pending |
| #894 | assertj-core 3.26 → 3.27.6 | ⏳ pending |
| #871 | maven-release-plugin 3.0.1 → 3.1.1 | ⏳ pending |
| #863 | maven-jar-plugin 3.4.1 → 3.4.2 | ⏳ pending |
| PR | Bump | Reason |
|---|---|---|
| #896 | JUnit Jupiter 5.10 → 6.0.0 | ❌ Closed — breaking major version; staying on JUnit 5.x |
| #895 | fmt-maven-plugin 2.24 → 2.29 | Formatter upgrade may reformat all source — skip until a dedicated cleanup PR is planned |
| #912 | javafx-swing 11 → 26-ea+13 | Early-access build; CI failure |
| PR | Title | State | Analysis status |
|---|---|---|---|
| #847 | Custom pie chart label generator | MERGEABLE / CLEAN / APPROVED | ⏳ in review — demo: TestForPR847.java |
| #864 | Fix #593 | MERGEABLE / CLEAN | ✅ merged — demo: TestForIssue593.java |
| #866 | Horizontal bar chart (new type) | MERGEABLE / CLEAN | ✅ merged — demo: TestForPR866.java |
| #888 | Fix chart-update freeze (#886) | CONFLICTING — needs rebase | ✅ merged — cherry-picked 2 Java files, excluded pom noise — demo: TestForIssue886.java |
| #885 | Refactor code smells | MERGEABLE / CLEAN | ⏳ not started |
| #913 | Decompose Utils + CSVImporter (SRP) | MERGEABLE / CLEAN | ⏳ not started |
| #917 | Grouped/merged Y-axes | UNSTABLE | ⏳ not started |
| PR | Notes |
|---|---|
| #641 | Draft for 3 years; may be superseded |
| #520 | 5+ years old; mergeable state unknown |
| #314 | 6+ years old; large XYSeries refactor; likely needs full rewrite |