I am using JFreeCharts to plot a scatterplot in Java. I am using PolynomialFunction2D to plot a quadratic regression line, over the scatterplot.
PolynomialFunction2D can be used to plot quadratic curves, that are defined as a function of x, ie, y = a0 + a1 * x + a2 * x^2 + ...
I want to plot a quadratic curve as a function of y, ie, x = a0 + a1 * y + a2 * y^2 + ... on the scatterplot, made in JFreeCharts, when the coefficients are given.
Is this possible? And, if yes, what approach can be used for the same.
You can create an XYSeries from the function, by manually sampling the function over y and computing the corresponding x-value. The resulting data set can be added to the XYPlot, together with the XYDataset of the scatter plot:
As an example:
import java.awt.Dimension;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.function.Function2D;
import org.jfree.data.function.PolynomialFunction2D;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
public class FunctionOfYOverScatter
{
public static void main(String[] args)
{
new FunctionOfYOverScatter();
}
public FunctionOfYOverScatter()
{
XYPlot plot = new XYPlot();
XYDataset scatterPlotDataset = getScatterPlotDataset();
plot.setDataset(0, scatterPlotDataset);
plot.setRenderer(0, new XYLineAndShapeRenderer(false, true));
plot.setDomainAxis(0, new NumberAxis("Scatterplot domain"));
plot.setRangeAxis(0, new NumberAxis("Scatterplot range"));
plot.mapDatasetToDomainAxis(0, 0);
plot.mapDatasetToRangeAxis(0, 0);
double minY = -2.0;
double maxY = 2.0;
XYDataset functionDataset =
getFunctionDataset(0.8, 0.5, 1.2, minY, maxY);
plot.setDataset(1, functionDataset);
plot.setRenderer(1, new XYLineAndShapeRenderer(true, false));
JFreeChart chart = new JFreeChart("Function of Y over scatter plot",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(500, 270));
ApplicationFrame frame = new ApplicationFrame("Example");
frame.setContentPane(chartPanel);
frame.pack();
frame.setVisible(true);
}
private XYDataset getFunctionDataset(
double a0, double a1, double a2,
double minY, double maxY)
{
double[] a = { a0, a1, a2 };
Function2D p = new PolynomialFunction2D(a);
XYSeries series = sampleFunctionOverY(p, minY, maxY, 100, "Function");
XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series);
return dataset;
}
public static XYSeries sampleFunctionOverY(Function2D f, double start,
double end, int samples, Comparable<?> seriesKey)
{
XYSeries series = new XYSeries(seriesKey, false);
double step = (end - start) / (samples - 1);
for (int i = 0; i < samples; i++)
{
double y = start + step * i;
series.add(f.getValue(y), y);
}
return series;
}
private XYDataset getScatterPlotDataset()
{
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries data = new XYSeries("Scatterplot");
data.add(3.0, 2.0);
data.add(1.7, 1.0);
data.add(2.0, -1.0);
data.add(1.0, 1.8);
dataset.addSeries(data);
return dataset;
}
}
Related
I'm trying to write a plotter class to display a set of data points (x, y, z) stored in an array using Jzy3d. The class should contain a method plot() that takes the data set and (automatically) displays it in a 3d coordinate system.The method is supposed to be called sequentially in a time-dependent loop.
So far I have managed get a scatter plot demo for Jzy3d working but I don't know what each bit of the code does. The documentation of Jzy3d doesn't provide that much information and I can't really to find any tutorials online.
It would be much appreciated if anyone can explain the demo or (even better) write a simple plotter that contains a similar method.
Any efficient working plotting alternatives to Jzy3d would be appreciated, too.
Demo code:
import java.util.Random;
import org.jzy3d.analysis.AbstractAnalysis;
import org.jzy3d.analysis.AnalysisLauncher;
import org.jzy3d.chart.factories.AWTChartComponentFactory;
import org.jzy3d.colors.Color;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.plot3d.primitives.Scatter;
import org.jzy3d.plot3d.rendering.canvas.Quality;
public class ScatterDemo extends AbstractAnalysis{
public static void main(String[] args) throws Exception {
AnalysisLauncher.open(new ScatterDemo());
}
#Override
public void init(){
int size = 500000;
float x;
float y;
float z;
float a;
Coord3d[] points = new Coord3d[size];
Color[] colors = new Color[size];
Random r = new Random();
r.setSeed(0);
for(int i=0; i<size; i++){
x = r.nextFloat() - 0.5f;
y = r.nextFloat() - 0.5f;
z = r.nextFloat() - 0.5f;
points[i] = new Coord3d(x, y, z);
a = 0.25f;
colors[i] = new Color(x, y, z, a);
}
Scatter scatter = new Scatter(points, colors);
chart = AWTChartComponentFactory.chart(Quality.Advanced, "newt");
chart.getScene().add(scatter);
}
}
this method should create new scatter
public void plot(Coord3d[] points, Color[] colors) {
Scatter scatter = new Scatter(points, colors);
chart = AWTChartComponentFactory.chart(Quality.Advanced, "newt");
chart.getScene().add(scatter);
}
this code shows how to create dataset, just use your values of coordinates and color
int size = 100
Coord3d[] points = new Coord3d[size];
Color[] colors = new Color[size];
for(int i=0; i < size; i++){
x = i;
y = i;
z = i;
points[i] = new Coord3d(x, y, z);
r = 0.5;
b = 0.5;
g = 0.5;
colors[i] = new Color(r, g, b);
}
hello guys i wonder why here in the code there is a line where i the procedure addChild(trans) is not attached to any place in the SimpleUniverse tree if someone cant explain me why that works and how it would be very helpful to me . thanks the (line is inseide the second for)
package examples;
import javax.media.j3d.Appearance;
import javax.media.j3d.Group;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3d;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Sphere;
public class SphereGroupExperiment extends Group{
Shape3D[] shapes;
int shapesNum=0;
public SphereGroupExperiment( )
{
// radius x,y spacing x,y count appearance
this(0.25f, 0.75f, 0.75f, 5, 5, null, false );
}
public SphereGroupExperiment( Appearance app )
{
// radius x,y spacing x,y count appearance
this( 0.25f, 0.75f, 0.75f, 5, 5, app, false );
}
public SphereGroupExperiment( float radius, float xSpacing, float ySpacing,
int xCount, int yCount, boolean overrideflag )
{
this( radius, xSpacing, ySpacing, xCount, yCount, null, overrideflag );
}
SphereGroupExperiment(float radius, float xSpace, float ySpace, int xCount, int yCount,Appearance app, boolean overrideFlag){
if(app == null){
Material material = new Material();
material.setDiffuseColor(new Color3f(0.0f, 1.0f, 0.0f));
material.setSpecularColor(new Color3f(0.0f, 0.0f, 0.0f));
material.setShininess(0.0f);
app.setMaterial(material);
}
double xStart = -xSpace * (double)(xCount-1)/2.0;
double yStart = -ySpace * (double)(yCount-1)/2.0;
Sphere sphare= null;
TransformGroup trans = null;
Transform3D t = new Transform3D();
Vector3d vec = new Vector3d();
double x, y = yStart, z = 0.0;
shapes = new Shape3D[xCount*yCount];
for (int i = 0 ; i<yCount ; i++){
x = xStart;
for(int j = 0; j<xCount; j++){
vec.set(x,y,z);
t.setTranslation(vec);
trans = new TransformGroup(t);
addChild(trans);
sphare = new Sphere(
radius, // sphere radius
Primitive.GENERATE_NORMALS, // generate normals
25, // 16 divisions radially
app ); // it's appearance
trans.addChild( sphare );
x += xSpace;
shapes[shapesNum] = sphare.getShape();
if (overrideFlag)
shapes[shapesNum].setCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE);
shapesNum++;
}
y += ySpace;
}
}
public Shape3D[] getSphares(){
return shapes;
}
}
Your class SphereGroupExperiment extends javax.media.j3d.Group. You will find addChild() in that class.
I am attempting to plot smooth curves where the points are close together (-4.0, 0.01), (-4.1, .02), and so on. The plot will have multiple lines and I would like to use dashed lines for each curve. I am using JFreeChart and have written a custom XYLineAndShapeRenderer to create dashed lines. However, the dashes do not always appear. It seems that the closer together the points in the dataset the fewer dashes I get. Does anyone know how I can use points that are close together and still get dashed lines? The code below demonstrates the problem. All of these lines should have dashes. I think the problem is related to the way Java draws lines with BasicStroke, but I am not sure.Thanks for your help!
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.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import javax.swing.*;
import java.awt.*;
public class IccGraph extends ApplicationFrame {
public IccGraph(String title){
super(title);
JPanel chartPanel = createPanel();
chartPanel.setPreferredSize(new Dimension(450, 400));
setContentPane(chartPanel);
}
private double probability(double x, double b){
double top = Math.exp(x-b);
double prob = top/(1+top);
return prob;
}
public XYSeriesCollection createData(){
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series1 = new XYSeries("Wide Points");
XYSeries series2 = new XYSeries("Close Points");
XYSeries series3 = new XYSeries("Very Close Points");
double maxValue = 4.0;
double value = -4.0;
double prob = 0.0;
//create series where x-axis values use increments of .5
//will produce graph with dashes as expected
while(value<maxValue){
prob = probability(value, -1.0);
series1.add(value, prob);
value += .5;
}
//create series where x-axis values use increments of .1
//will produce line with some dashes
value = -4.0;
while(value<maxValue){
prob = probability(value, 0.0);
series2.add(value, prob);
value += .1;
}
//create series where x-axis values use increments of .01
//will produce straight lines in graph
value = -4.0;
while(value<maxValue){
prob = probability(value, 1.0);
series3.add(value, prob);
value += .01;
}
dataset.addSeries(series1);
dataset.addSeries(series2);
dataset.addSeries(series3);
return dataset;
}
public JPanel createPanel(){
JFreeChart chart = createChart(createData());
ChartPanel panel = new ChartPanel(chart);
return panel;
}
public JFreeChart createChart(XYSeriesCollection dataset){
JFreeChart chart = ChartFactory.createXYLineChart(
"", // chart title
"Theta", // x axis label
"Probability", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(){
#Override
public Stroke getItemStroke(int row, int col){
Stroke dash1 = new BasicStroke(1.0f,
BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER,
10.0f,
new float[] {5.0f,5.0f},
0.0f);
return dash1;
}
};
renderer.setBaseShapesFilled(false);
renderer.setDrawOutlines(false);
XYPlot plot = (XYPlot)chart.getPlot();
plot.setRenderer(renderer);
return chart;
}
public static void main(String[] args) {
IccGraph graph = new IccGraph("Line Dash Problem");
graph.pack();
graph.setVisible(true);
}
OK, I found the answer. The solution is to use renderer.setDrawSeriesLineAsPath(true). The revised code listed below, plots three dashed lines as desired.
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.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import javax.swing.*;
import java.awt.*;
public class IccGraph extends ApplicationFrame {
public IccGraph(String title){
super(title);
JPanel chartPanel = createPanel();
chartPanel.setPreferredSize(new Dimension(450, 400));
setContentPane(chartPanel);
}
private double probability(double x, double b){
double top = Math.exp(x-b);
double prob = top/(1+top);
return prob;
}
public XYSeriesCollection createData(){
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series1 = new XYSeries("Wide Points");
XYSeries series2 = new XYSeries("Close Points");
XYSeries series3 = new XYSeries("Very Close Points");
double maxValue = 4.0;
double value = -4.0;
double prob = 0.0;
//create series where x-axis values use increments of .5
//will produce graph with dashes as expected
while(value<maxValue){
prob = probability(value, -1.0);
series1.add(value, prob);
value += .5;
}
//create series where x-axis values use increments of .1
//will produce line with some dashes
value = -4.0;
while(value<maxValue){
prob = probability(value, 0.0);
series2.add(value, prob);
value += .1;
}
//create series where x-axis values use increments of .01
//will produce straight lines in graph
value = -4.0;
while(value<maxValue){
prob = probability(value, 1.0);
series3.add(value, prob);
value += .01;
}
dataset.addSeries(series1);
dataset.addSeries(series2);
dataset.addSeries(series3);
return dataset;
}
public JPanel createPanel(){
JFreeChart chart = createChart(createData());
ChartPanel panel = new ChartPanel(chart);
return panel;
}
public JFreeChart createChart(XYSeriesCollection dataset){
JFreeChart chart = ChartFactory.createXYLineChart(
"", // chart title
"Theta", // x axis label
"Probability", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(){
#Override
public Stroke getItemStroke(int row, int col){
Stroke dash1 = new BasicStroke(1.0f,
BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER,
10.0f,
new float[] {10.0f,5.0f},
0.0f);
return dash1;
}
};
renderer.setBaseShapesFilled(false);
renderer.setDrawOutlines(false);
renderer.setDrawSeriesLineAsPath(true);//this line is the solution
XYPlot plot = (XYPlot)chart.getPlot();
plot.setRenderer(renderer);
return chart;
}
public static void main(String[] args) {
IccGraph graph = new IccGraph("Line Dash Problem");
graph.pack();
graph.setVisible(true);
}
}
I have a dataset of points (x,y) and I would like to create an heatmap of this dataset. More specifically, I would like an image in which I have lighter colors in the areas where I have a bigger concentration of points and darker where there are less points.
I am using JFreeChart libraries and I found some classes for example DefaultHeatMapDataset but I am not sure how to use them in the proper way.
Does anybody has a clue on how to do it?
Thanks in advance!
Giovanni
Use an XYBlockRenderer with a suitable implementation of XYZDataset and a corresponding implementation of PaintScale.
Creating a heatmap in JFreeChart is a bit tricky, as there is still (as of version 1.0.19/1.5.0) no chart-type resp. plot for this usecase. (The available HeatMapDataset was written to be used with HeatMapUtilities as David Gilbert wrote in the forum.)
So best way for creating a heatmap is using an XYPlot with an XYBlockRenderer and an XYZDataset, as trashgod already wrote.
Here is a complete, minimalistic example that you can run to get the chart shown below:
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import java.awt.*;
import java.util.Random;
public class HeatMapDemo extends ApplicationFrame
{
public HeatMapDemo()
{
super("JFreeChart Heatmap Demo");
final JFreeChart chart = createChart(createDataset());
setContentPane(new ChartPanel(chart));
}
private static JFreeChart createChart(XYZDataset dataset)
{
// x-axis for time
DateAxis xAxis = new DateAxis("Time");
xAxis.setStandardTickUnits(DateAxis.createStandardDateTickUnits());
xAxis.setLowerMargin(0);
xAxis.setUpperMargin(0);
// visible y-axis with symbols
String labels[] = new String[500];
for (int i = 0; i < 500; i++)
labels[i] = "ca. " + i + "nm";
SymbolAxis yAxis = new SymbolAxis(null, labels);
yAxis.setTickUnit(new NumberTickUnit(50));
// another invisible y-axis for scaling
// (this is not necessary if your y-values are suitable)
NumberAxis valueAxis1 = new NumberAxis("Marker");
valueAxis1.setLowerMargin(0);
valueAxis1.setUpperMargin(0);
valueAxis1.setVisible(false);
// create a paint-scale and a legend showing it
LookupPaintScale paintScale = new LookupPaintScale(0, 300, Color.black);
Color c = Color.green;
paintScale.add(0.0, c);
paintScale.add(33.0, c = c.darker());
paintScale.add(66.0, c.darker());
paintScale.add(100.0, c = Color.blue);
paintScale.add(133.0, c = c.darker());
paintScale.add(166.0, c.darker());
paintScale.add(200.0, c = Color.red.darker().darker());
paintScale.add(233.0, c = c.brighter());
paintScale.add(266.0, c.brighter());
PaintScaleLegend psl = new PaintScaleLegend(paintScale, new NumberAxis());
psl.setPosition(RectangleEdge.RIGHT);
psl.setAxisLocation(AxisLocation.TOP_OR_RIGHT);
psl.setMargin(50.0, 20.0, 80.0, 0.0);
// finally a renderer and a plot
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, new XYBlockRenderer());
((XYBlockRenderer)plot.getRenderer()).setPaintScale(paintScale);
// 2 optional lines, depending on your y-values
plot.setRangeAxis(1, valueAxis1);
plot.mapDatasetToRangeAxis(0, 1);
JFreeChart chart = new JFreeChart(null, null, plot, false);
chart.addSubtitle(psl);
return chart;
}
public XYZDataset createDataset()
{
double[] xvalues = new double[1000*100]; // date
double[] yvalues = new double[1000*100]; // numeric (1-100)
double[] zvalues = new double[1000*100]; // numeric (the actual data)
// create some random data
final Random rand = new Random();
long l = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
l -= 600000;
for (int j = 0; j < 100; j++) {
final int idx = i * 100 + j;
xvalues[idx] = l;
yvalues[idx] = j;
double delta = rand.nextInt(15) * (rand.nextInt(4) == 0 ? -1 : 1);
zvalues[idx] = Math.max(0, Math.min(300,
(idx < 1000 ? 0 : zvalues[idx - 1000]) + delta));
}
}
DefaultXYZDataset dataset = new DefaultXYZDataset();
dataset.addSeries("Just one Series", new double[][] { xvalues, yvalues, zvalues });
return dataset;
}
public static void main(String args[])
{
final HeatMapDemo demo = new HeatMapDemo();
demo.pack();
demo.setVisible(true);
}
}
The produced heatmap looks like this:
If you need a more linear PaintScale, you could have a look a the SpectrumPaintScale implementation in this answer.
This is my First Month with Java, so I apologize for my stupid question in advance. I'm trying to make a simple program using Jfreechart. I want to display my 2D array on the scatter plot.
here is the code:
package myappthatusesjfreechart;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.general.DefaultPieDataset;
public class MyAppThatUsesJFreeChart {
public static void main(String[] args) {
// create a dataset...
int[][] a2 = new int[10][5];
// print array in rectangular form
for (int r = 0; r < a2.length; r++) {
for (int c = 0; c < a2[r].length; c++) {
System.out.print(" " + a2[r][c]);
}
System.out.println("");
}
// create a chart...
JFreeChart chart = ChartFactory.createScatterPlot(
"Scatter Plot", // chart title
"X", // x axis label
"Y", // y axis label
a2, // data ***-----PROBLEM------***
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
// create and display a frame...
ChartFrame frame = new ChartFrame("First", chart);
frame.pack();
frame.setVisible(true);
}
}
The ;ChartFactory.createScatterPlot; is not allowing me to pass the 2d array, I want to ask is there any way that i can do it.
The createScatterPlot() method expects an XYDataset, such as XYSeriesCollection. There are examples using XYSeriesCollection here and here.
Addendum: Here's an example more suited to a scatter plot; just replace a2 with createDataset() in the factory call.
private static final Random r = new Random();
private static XYDataset createDataset() {
XYSeriesCollection result = new XYSeriesCollection();
XYSeries series = new XYSeries("Random");
for (int i = 0; i <= 100; i++) {
double x = r.nextDouble();
double y = r.nextDouble();
series.add(x, y);
}
result.addSeries(series);
return result;
}