A minimal, extensible Java project showcasing plotting with
the XChart library, starting with
line plots and histograms implemented in
LinePlots.java and Histograms.java.
Future extensions can include additional plot types such as scatter plots, pie charts, and more.
Built with Java, Maven, XChart, and Swing.
- About this repository
- What is XChart and how do we plot in Java?
- Installing prerequisites: Java and Maven
- Installing XChart library
- Project structure
- Building and running with Maven
- Building and running without Maven
- mvn compile vs mvn clean compile
- LinePlots.java module (line plots)
- Histograms.java module (histograms)
- exec:java and Java2D rendering flags
- Running different main classes
- Implementation tutorial video
This repository is a small but extensible playground for plotting in Java using the XChart library.
Current examples:
LinePlots.java— multiple line-plot demonstrations (multi-series plots, markers, subplots via grid layouts, etc.).Histograms.java— various histogram use-cases (different binning rules, normalization modes, categorical histograms, overlays, etc.).
The layout is intentionally modular, so you can:
- Add new plot types (e.g., scatter, pie, bar) as separate
*.javaclasses. - Extend this README by adding new sections using the same structure as the LinePlots and Histograms sections.
XChart is a light-weight Java plotting library that uses Swing for interactive windows and supports:
- Line charts, scatter plots, histograms, bar charts, pie charts, etc.
- Simple API for building charts and embedding them in Swing applications.
- Export to image formats (PNG, JPG, etc.) and vector formats (SVG, EPS) via additional modules.
This repository uses:
XYChartfor line plots (LinePlots.java).CategoryChartfor histograms (Histograms.java).XChartPanelto embed charts inside Swing containers (JFrame+JTabbedPane).
Below is a minimal code snippet showing how to build and display a line chart using XChart and Swing:
import org.knowm.xchart.XYChart;
import org.knowm.xchart.XYChartBuilder;
import org.knowm.xchart.XChartPanel;
import javax.swing.*;
import java.util.Arrays;
public class SimpleLineExample {
public static void main(String[] args) {
double[] x = {0.0, 1.0, 2.0, 3.0};
double[] y = {0.0, 1.0, 4.0, 9.0};
XYChart chart = new XYChartBuilder()
.width(600)
.height(400)
.title("y = x^2")
.xAxisTitle("x")
.yAxisTitle("y")
.build();
chart.addSeries("x^2", x, y);
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("XChart example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new XChartPanel<>(chart));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}In this repo, we generalize that pattern to multiple charts, all shown in a single window with tabs (for line plots and histograms).
To save a chart visually, right-click on the chart area and choose “Save As…” or use the keyboard shortcut (usually Ctrl+S) while the chart has focus.
You will need:
- A Java Development Kit (JDK) 8 or later (JDK 17+ recommended).
- Apache Maven (build system and dependency manager).
- Git Bash (for running the example commands on Windows, as shown here).
-
Download and install a JDK (e.g., from Adoptium, Oracle, etc.).
-
Ensure
javaandjavacare on your PATH:java -version javac -version
Both commands should print a version and not “command not found”.
-
Download Maven from the official Apache Maven site.
-
Unzip/Install it and add the
binfolder to your PATH. -
Verify installation:
mvn -version
You should see Maven’s version and the Java version it uses.
Once Java and Maven are installed, you can clone this repository and build/run the examples directly.
There are two common ways to use XChart:
-
Via Maven (recommended)
Maven downloads and manages the XChart JAR automatically. -
Manual JAR download (non-Maven projects)
You download the JAR and add it to your classpath manually.
In pom.xml we declare XChart as a dependency:
<dependencies>
<dependency>
<groupId>org.knowm.xchart</groupId>
<artifactId>xchart</artifactId>
<version>3.8.8</version>
</dependency>
</dependencies>When you run mvn compile, Maven will automatically download XChart (and its transitive dependencies) into your local repository (~/.m2/repository) and place it on the classpath for compilation and execution.
If you are not using Maven, you can:
-
Download the
xchart-3.8.8.jarfile from Maven Central or the XChart website. -
Compile and run with
-cp(class path), for example on Windows:javac -cp .;path\to\xchart-3.8.8.jar LinePlots.java java -cp .;path\to\xchart-3.8.8.jar LinePlots
On Linux/macOS, the classpath separator is
:instead of;:javac -cp .:path/to/xchart-3.8.8.jar LinePlots.java java -cp .:path/to/xchart-3.8.8.jar LinePlots
In this repository we strongly recommend Maven, as it is already configured.
A minimal view of the project tree:
Java_Plot/
├── pom.xml
└── src
└── main
└── java
├── LinePlots.java
└── Histograms.java
-
pom.xml
Maven configuration file. Declares the project coordinates (groupId,artifactId,version), dependencies (XChart), and theexec-maven-pluginto run Javamainclasses from the command line. -
src/main/java/LinePlots.java
Contains all line plot examples.
It builds multipleXYChartobjects and shows them in a singleJFramewith aJTabbedPane(tabs 1–6). -
src/main/java/Histograms.java
Contains all histogram examples.
It builds multipleCategoryChartobjects, including a2×3grid of charts for comparing binning rules, again shown in a tabbed window.
You can add more plot examples by creating new Java files in src/main/java/ and wiring them via Maven or by running them directly.
All commands below assume you are in the project root (Java_Plot), e.g., in Git Bash:
cd ~/Desktop/Java_Plotmvn compileThis:
- Compiles all Java sources in
src/main/java/intotarget/classes/. - Downloads dependencies (XChart) if not already present.
pom.xml is configured with an exec-maven-plugin that defines a named execution for line plots:
<execution>
<id>line-plots</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>LinePlots</mainClass>
</configuration>
</execution>To run it:
mvn exec:java@line-plotsThis launches the line-plot GUI (LinePlots.main) with one window and 6 tabs.
Similarly, pom.xml contains:
<execution>
<id>histograms</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>Histograms</mainClass>
</configuration>
</execution>To run it:
mvn exec:java@histogramsThis launches the histogram GUI (Histograms.main) with one window and 7 tabs (one of them is a 2×3 grid).
Although Maven is recommended, you can still compile and run manually with javac and java, provided that XChart is on the classpath.
Assume that:
- The project root is
Java_Plot/. - The XChart JAR is located at
lib/xchart-3.8.8.jar(you may choose a different path).
From Java_Plot:
javac -cp .;lib\xchart-3.8.8.jar src\main\java\LinePlots.java src\main\java\Histograms.javaOn Linux/macOS, use : as the separator:
javac -cp .:lib/xchart-3.8.8.jar src/main/java/LinePlots.java src/main/java/Histograms.javaThis will place .class files alongside the .java files unless you specify -d for a custom output directory.
On Windows:
java -cp .;lib\xchart-3.8.8.jar;src\main\java LinePlots
java -cp .;lib\xchart-3.8.8.jar;src\main\java HistogramsOn Linux/macOS:
java -cp .:lib/xchart-3.8.8.jar:src/main/java LinePlots
java -cp .:lib/xchart-3.8.8.jar:src/main/java HistogramsNote: Using Maven avoids all of this manual classpath management, which is why the project is Maven-based.
Two commonly used Maven commands:
- Compiles the source code in
src/main/javainto thetarget/classesdirectory. - Recompiles only what changed (incremental compilation).
- Does not delete the
targetdirectory. - Ideal for normal, iterative development.
mvn cleandeletes thetargetdirectory completely.- Maven then runs
compilefrom a fresh state. - Helpful when:
- You change dependencies or plugin versions in
pom.xml. - You update Java versions or compiler flags.
- You suspect there might be stale
.classfiles causing odd behavior.
- You change dependencies or plugin versions in
As a rule of thumb:
- For everyday modifications →
mvn compileand thenmvn exec:java@... - After big configuration changes or mysterious build issues →
mvn clean compile
You do not need to manually delete the target folder; Maven’s clean goal takes care of that for you.
LinePlots.java is the Java code for making line plots in Java. It showcases multiple line-plot patterns using XChart and a Swing tabbed window.
-
main(String[] args)- Creates all charts (pure computation, no Swing yet):
createMultipleLineChart()createSetOfVectorsChart()createSinLinesChart()createSinLinesWithMarkersChart()createTiledCharts()(2×1 layout of two charts)createSubplots3x2()(6 charts assembled in a 3×2 grid)
- Calls
buildAndShowUI(...)viaSwingUtilities.invokeLater(...)to ensure Swing runs on the Event Dispatch Thread.
- Creates all charts (pure computation, no Swing yet):
-
buildAndShowUI(...)- Creates a
JFrame("Java_Plot – XChart demo"). - Creates a
JTabbedPane. - Adds 6 tabs:
- Multiple line plots
- Set-of-vectors plots
- sin(x) function line plots
- sin(x) function line plots with markers
- 2×1 layout (top/bottom)
- 3×2 grid (6 charts)
- Each tab contains one or more
XChartPanel<?>instances. - Packs and displays the frame.
- Creates a
-
Helper UI methods:
wrapSingleChart(XYChart chart)– wraps a single chart in aJPanelwithBorderLayout.wrapChartGrid(List<XYChart> charts, int rows, int cols)– builds aGridLayoutwith multiple charts, used for examples 5 and 6.createBaseChart(...)– factory forXYChartobjects with common styling (legend, tooltips, decimal patterns for axes).
-
Numeric helpers:
linspace(double start, double end, int num).apply(double[] x, DoubleUnaryOperator op)– applies a function to all elements ofx.
createMultipleLineChart():
- Generates
xin[0, 2π]usinglinspace. - Computes:
sin(x)-sin(x)x/π - 1
- Adds an additional manual sequence of values:
- x: 0,1,2,3,4,5,6
- y: 1.0, 0.7, 0.4, 0.0, -0.4, -0.7, -1.0
- Shows how to:
- Use different markers (
CIRCLE,DIAMOND,SQUARE,CROSS). - Use different line styles (
SOLID,DASH_DASH,DOT_DOT). - Format axes to 2 decimal places.
- Use different markers (
createSetOfVectorsChart():
- Hard-codes four numeric rows (analog of
std::set<std::vector<double>>). - Uses a simple x-axis of 1, 2, 3, 4.
- Plots each row as a separate series with distinct markers.
- Sets both axes to integer labels (
"0"decimal pattern).
createSinLinesChart():
sin(x),sin(x - 0.25),sin(x - 0.5)forxin[0, 2π].- Each series has a different line style and no markers.
- Demonstrates multi-series line charts sharing the same x-axis.
createSinLinesWithMarkersChart():
- Same general functions as example 3 but:
- Fewer sample points for clearer markers.
- Different markers and colors for each series.
- Good reference for customizing markers and styles per series.
createTiledCharts():
- Creates two charts:
- Top:
sin(5x) - Bottom:
sin(15x)
- Top:
- These charts are assembled in a
GridLayout(2, 1)bywrapChartGrid(...)and displayed on tab 5.
createSubplots3x2():
Builds a list of 6 charts:
sin(x)tan(sin(x)) - sin(tan(x))cos(5x)- Time-like data (0 to 180) with sample values
sin(5x)- A circle drawn via parametric equations (
x = r cos θ + x_c,y = r sin θ + y_c)
These six charts are placed in a GridLayout(3, 2) panel and shown as tab 6.
Histograms.java is the Java code for making histogram charts in Java. It uses CategoryChart to represent histograms and a small helper class HistogramData to store bin centers, counts, and widths.
-
main(String[] args):- Generates charts for:
- Basic histogram of N(0,1).
- Six sub-histograms comparing binning algorithms.
- Histogram with a fixed number of bins (50).
- Histogram with custom bin edges and count-density normalization.
- Categorical histogram (string responses).
- Overlaid normalized histograms (probability).
- Histogram normalized to PDF with theoretical normal PDF overlay.
- Displays them in a
JFramewith aJTabbedPane, one tab per “example”. Example 2 uses a nested2×3grid of charts in one tab.
- Generates charts for:
-
HistogramData(inner static class):- Holds:
double[] binCentersdouble[] binCountsdouble[] binWidthsdouble totalCount
- Constructed by helper functions that compute histograms from raw samples.
- Holds:
-
Random generator:
randn(int n, double mean, double stdDev)– usesRandom.nextGaussian()to generate normal samples.
-
Basic statistics and binning utilities:
min,max,mean,stdDev,percentile- Binning rules:
fdBinCount(...)— Freedman–Diaconis rule.scottBinCount(...)— Scott’s rule.sturgesBinCount(...)— Sturges’ rule.sqrtBinCount(...)— square-root rule.integerEdges(...)— integer-bin edges for the “integers” rule.
-
Histogram building utilities:
uniformBinHistogram(...)anduniformBinHistogramInRange(...)— build histograms with a fixed number of equally spaced bins.histogramWithBinWidth(...)— builds bins of fixed width over a given range.histogramWithCustomEdges(...)— uses explicit bin edges.
-
Chart construction helpers:
createEmptyHistogramChart(...)— baseCategoryChartskeleton with axes titles, legend, decimal patterns.createHistogramChartFromData(...)— builds aCategoryChartfromHistogramDataplus chart labels.
createHistogram1():
- Generates 10,000 samples from N(0,1).
- Uses Freedman–Diaconis (
fdBinCount) as an “automatic” bin-count estimate. - Builds a histogram with integer counts and 2-decimal x-axis labels.
- Logs the number of bins to the console.
createHistogram2BinningComparisonCharts():
- Generates 10,000 samples from N(0,1).
- Builds six histograms, each using a different binning strategy:
- “Automatic” (here chosen as FD).
- Scott’s rule.
- Freedman–Diaconis rule explicitly.
- Integers rule (integer bin edges).
- Sturges’ rule.
- Square-root rule.
- Each histogram is a separate
CategoryChartwith its own title. createBinningGridPanel(...)assembles them into a2×3GridLayoutand places that panel in tab 2.
createHistogram3():
- Generates 1,000 samples from N(0,1).
- Uses a fixed bin count of 50 directly.
- Sets the chart title to
"<numBins> bins".
Dynamic rebinning over time (with sleep) is not reproduced here to keep the Java GUI responsive and simpler; instead, the Java version shows the final 50-bin configuration.
createHistogram4():
- Generates 10,000 samples from N(0,1).
- Uses the explicit custom bin edges.
- Computes
count_density = count / bin_widthfor each bin. - Plots count density vs. bin center as a
CategoryChart. - Y-axis is formatted with
0.00decimal pattern.
createHistogram5Categorical():
- Uses an array of
"yes","no", and"undecided"strings. - Builds a frequency map (
Map<String, Integer>). - Plots a bar chart where categories are
"no","yes","undecided"in a fixed order.
createHistogram6OverlaidProbability():
- Generates two normal samples:
- 2,000 from N(0,1)
- 5,000 from N(1,1)
- Determines a global
[min, max]and uses a common bin width (0.25) for both datasets. - Computes probability for each bin:
count_i / total_count. - Uses
CategoryChartwithsetOverlapped(true)so bars from both distributions overlay each other. - Legend indicates which distribution is which.
createHistogram7PdfOverlay():
- Generates 5,000 samples from N(μ=5, σ=2).
- Builds a histogram over the range [-5, 15] with fixed bin width (0.5).
- Computes an empirical PDF:
count_i / (N * bin_width_i). - Computes the theoretical normal PDF at bin centers using:
normalPdf(x, mu, sigma).
- Plots the empirical PDF as bars and the theoretical PDF as a line (
CategorySeriesRenderStyle.Line).
You may see two forms of the exec:java command:
mvn exec:java@histogramsand
mvn exec:java@histograms -Dexec.jvmArgs="-Dsun.java2d.d3d=false -Dsun.java2d.opengl=false"This:
- Uses the JVM with default Java2D settings.
- On most machines, hardware acceleration (Direct3D / OpenGL) is enabled by default.
- Is usually what you want.
Sometimes, due to graphics driver or JDK issues, Swing windows that use Java2D can render as blank/white windows even though the program is running. To work around such issues, you can disable hardware acceleration:
mvn exec:java@histograms -Dexec.jvmArgs="-Dsun.java2d.d3d=false -Dsun.java2d.opengl=false"The JVM arguments:
-Dsun.java2d.d3d=false— disables Direct3D-based acceleration (Windows).-Dsun.java2d.opengl=false— disables OpenGL-based acceleration.
Use this variant only if you see rendering glitches (white windows, flickering, etc.). For most users, the default mvn exec:java@... is sufficient.
There are two primary ways to choose which main class to run.
With the exec-maven-plugin configured as:
<execution>
<id>line-plots</id>
<goals><goal>java</goal></goals>
<configuration>
<mainClass>LinePlots</mainClass>
</configuration>
</execution>
<execution>
<id>histograms</id>
<goals><goal>java</goal></goals>
<configuration>
<mainClass>Histograms</mainClass>
</configuration>
</execution>you can run each one explicitly:
mvn exec:java@line-plots
mvn exec:java@histogramsThis is the approach used by this repository and is usually the cleanest.
You can also use the generic exec:java goal and override the mainClass via -Dexec.mainClass=...:
mvn exec:java -Dexec.mainClass=LinePlots
mvn exec:java -Dexec.mainClass=HistogramsThis can be handy when experimenting or when you haven’t defined named executions yet. However, once you have multiple examples, the named executions (@line-plots, @histograms) make your workflow clearer and easier to document.
A video tutorial about how to compile this repository and making plots with Java.