I want to make a discrete signal plot in Java, like when using the stem() command in matlab, such that when giving it an array for the x-axis and one for the y-axis, it makes like a scatter plot with a vertical line connected to x-axis.
I have tried using JFreeChart to do this, but it doesn't have a discrete plot specifically. The closest I came to it was asking ChatGPT to make a scatter plot and connect the lines to the bottom and it gave me this code:
package z;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import javax.swing.SwingUtilities;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
public class ScatterPlotWithLines extends ApplicationFrame {
public ScatterPlotWithLines(String title) {
super(title);
// Create a dataset with 10 random data points
XYSeriesCollection dataset = createScatterDataset(10);
// Create the scatter plot
JFreeChart chart = ChartFactory.createScatterPlot(
"Scatter Plot with Lines",
"X-Axis Label",
"Y-Axis Label",
dataset,
PlotOrientation.VERTICAL,
true,
true,
false
);
// Customize the plot and renderer for scatter points (optional)
XYPlot plot = (XYPlot) chart.getPlot();
XYItemRenderer renderer = plot.getRenderer();
// Customize the renderer for scatter points (e.g., change the shape and color of points)
Shape pointShape = new Ellipse2D.Double(-3, -3, 6, 6); // Example shape
renderer.setSeriesShape(0, pointShape);
renderer.setSeriesPaint(0, Color.blue);
// Create a dataset for lines connecting the data points to the x-axis
DefaultXYDataset lineDataset = createLineDataset(dataset);
// Create a renderer for the lines
XYItemRenderer lineRenderer = new XYLineAndShapeRenderer(true, false);
lineRenderer.setSeriesPaint(0, Color.red); // Line color
plot.setDataset(1, lineDataset); // Add the line dataset to the plot
plot.setRenderer(1, lineRenderer); // Set the line renderer for the new dataset
// Set margin for the plot
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
// Create a ChartPanel and add it to the frame
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(800, 600));
setContentPane(chartPanel);
}
private XYSeriesCollection createScatterDataset(int numPoints) {
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series = new XYSeries("Scatter Plot");
// Generate random data points for the series
Random rand = new Random();
for (int i = 0; i < numPoints; i++) {
double x = rand.nextDouble() * 10;
double y = rand.nextDouble() * 10;
series.add(x, y);
}
dataset.addSeries(series);
return dataset;
}
private DefaultXYDataset createLineDataset(XYSeriesCollection scatterDataset) {
DefaultXYDataset lineDataset = new DefaultXYDataset();
// Create lines connecting data points to the x-axis
for (int i = 0; i < scatterDataset.getSeriesCount(); i++) {
XYSeries scatterSeries = scatterDataset.getSeries(i);
double[][] lineData = new double[2][scatterSeries.getItemCount() * 2];
for (int j = 0; j < scatterSeries.getItemCount(); j++) {
double x = scatterSeries.getX(j).doubleValue();
double y = scatterSeries.getY(j).doubleValue();
// Add the data point
lineData[0][j * 2] = x;
lineData[1][j * 2] = y;
// Connect to the x-axis
lineData[0][j * 2 + 1] = x;
lineData[1][j * 2 + 1] = 0;
}
lineDataset.addSeries("Lines", lineData);
}
return lineDataset;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
ScatterPlotWithLines example = new ScatterPlotWithLines("Scatter Plot with Lines");
example.pack();
example.setDefaultCloseOperation(ApplicationFrame.EXIT_ON_CLOSE);
example.setVisible(true);
});
}
}
and it works, sort of:
I understand it made a different dataset and connected the dots, but is it possible to have it just with the vertical lines? I know I can do this easily using other languages like Python and MatLab, I just want to know if it's possible to do it in Java.

As @Ahmed AEK comments, you can adjust your dataset to "make it look more like stem." Also consider,
HighLowRenderer, suitable for continuous data; the methodssetDrawCloseTicks()andsetDrawOpenTicks()control tick mark visibility.MinMaxCategoryRenderer, suitable for category data; the icons can be replaced with custom implementations, as seen here and here.