This question already has answers here:
Logarithmic Axis Labels/Ticks Customization
(3 answers)
Closed 6 years ago.
I am using JFree to generate my chart. Below is the image for your reference. As visible in image current scale is based on 10 so 10,100,1000 are there in x-axis scale. Would it possible to change it to log 2. So in case of log 2 point would be visible 2,4,8,16,32, 64 and so on. Class LogarithmicAxis.java is being used for rendering x-axis.
Please let me know if its possible
Below code generate log 2 scale but I am not able to set x-axis point vertically which is very important for me.
public class TestHello {
/** #see http://stackoverflow.com/a/10353270/230513 */
private static void createFrame() {
int N=22;
XYSeries series = new XYSeries("Series");
for (int i = 0; i <= N; i++) {
System.out.println(Math.pow(2, i));
Random r = new Random();
double randomInt = r.nextInt(100) + 1;
series.add(Math.pow(2, i),randomInt);
}
NumberAxis yAxis = new NumberAxis("Y");
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
LogAxis xAxis = new LogAxis("X");
xAxis.setBase(2);
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
xAxis.setVerticalTickLabels(true);
JFreeChart chart = ChartFactory.createXYLineChart(
"Text", "x", "y", new XYSeriesCollection(series),
PlotOrientation.VERTICAL, true, true, false);
final XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setDomainAxis(xAxis);
plot.setRangeAxis(yAxis);
final Marker start = new ValueMarker(60.0);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
renderer.setLegendLine(new Line2D.Double(-20.0D, 0.0D, 20.0D, 0.0D));
Shape square = new Rectangle2D.Double(-2.0, -2.0, 3.0, 3.0);
renderer.setSeriesShape(0, square);
plot.setRenderer(renderer);
plot.addRangeMarker(start);
JFrame frame = new JFrame("LogAxis Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new ChartPanel(chart));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createFrame();
}
});
}
}
Try using the LogAxis class rather than the LogarithmicAxis class (there are two, for historical reasons) and call axis.setBase(2.0) when you set up the axis.
Related
I am trying to obtain the equivalent of a matlab Pcolor added on a polar() function but in java.
I am pretty new to the language, but managed to obtain a polar plot already, with the following code:
public class Polar extends JFrame {
public Polar(double[][] vec){
XYDataset dataset = getXYDataset(vec);
JFreeChart chart = ChartFactory.createPolarChart("test", dataset, true, true, true);
PolarPlot plot = (PolarPlot) chart.getPlot();
DefaultPolarItemRenderer render = (DefaultPolarItemRenderer)
plot.getRenderer();
render.setFillComposite(...);
render.setSeriesFilled(0,true);
ChartPanel panel = new ChartPanel(chart);
panel.setMouseZoomable(false);
setContentPane(panel);
}
private XYDataset getXYDataset(double[][] vec){
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries faultDP =new XYSeries("Serie1");
for(int i = 0; i<vec.length; i++){
faultDP.add(vec[i][1],vec[i][0]);
}
dataset.addSeries(faultDP);
return dataset;
}
}
The array vec contains the speed and angle of my variable, and should be plotted on the polar plot. this works fine.
The next step would be to pass a new variable, a double[][] vector of dimension 90x360. Each cell should be plotted on the polar plot with background color value, a bit like in the picture below.
Any idea on how to do so ?
Cheers,
Flo
So, I've looked into what trashgod offered me and came with this code:
public class PolarTest extends JFrame {
public PolarTest(double[][] dipaz, double[][] val){
JFrame f = new JFrame("Title");
ChartPanel panel = new ChartPanel(createChart(val, dipaz));
panel.setPreferredSize(new Dimension(500,500));
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JFreeChart createChart(double[][] val,double[][] dipaz){
XYSeriesCollection dataset = new XYSeriesCollection ();
double step, min, max;
min = val[0][2];
max = val[val.length-1][2];
step = (max-min)/10; //creation of 10 areas of similar heat range
dataset = (XYSeriesCollection) createDataset(val,step);
JFreeChart chart = ChartFactory.createPolarChart("test", dataset, true, true, true);
PolarPlot plot = (PolarPlot) chart.getPlot();
DefaultPolarItemRenderer r = (DefaultPolarItemRenderer) plot.getRenderer();
r.setFillComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f));
for(int i =0; i<dataset.getSeriesCount(); i++){
r.setSeriesFilled(i, true);
r.setShapesVisible(false);
r.setDrawOutlineWhenFilled(false);
}
NumberAxis rangeAxis = (NumberAxis) plot.getAxis();
rangeAxis.setTickLabelsVisible(false);
return chart;
}
private XYDataset createDataset(double[][] val, double step){
XYSeriesCollection result = new XYSeriesCollection();
double dpTmp, breakPoint;
int cpt=1;
boolean t;
t= true;
dpTmp = val[0][2];
breakPoint = dpTmp + step;
XYSeries series = null ;
for(int i = 0; i< val.length; i++){
if(val[i][2] < breakPoint){
if(t){
series = new XYSeries(String.valueOf(cpt));
t = false;
}
series.add(val[i][1],val[i][0]);
cpt++;
}else{
result.addSeries(series);
i--;
t=true;
breakPoint = val[i][2] + step;
}
}
return result;
}
The array dipaz contains my angle and dip (of X,Y dots I'd like to later plot on the polar representation), while val a 3 by N array:
val[][0] = dip
val[][1] = angle
val[][2] = value of "heat" , if we see that problem as a heatmap.
val is ascending sorted by the third column. My idea was to split the whole array in 10 (or more) areas of similar heat values.
if I run this code, I obtain the following output (cf pic). We can see that it's getting there, but not quite. I am not sure that this code is able to map correctly my heat on the polar plot>
How could I get closer to the picture I posted in my first post?
Thank you for your help.
Flo
I am trying to understand how the StackedAreaChart colors its series, in order to color series consistently in my application when data is replaced with entirely new data. Initially, I thought StackedAreaChart cycles through 8 default colors. In other words, data series are colored according to their index in getData(), mod 8. But I am encountering unexpected behavior:
The output above comes from the application below, which clears the StackedAreaChart's data and repopulates it with 10 new series every time the window is clicked. As you can see, only the first 8 colors are consistent across clicks/repopulations.
public class TestChartColors extends Application {
private int clickCount = 0;
#Override
public void start(Stage primaryStage) {
NumberAxis xAxis = new NumberAxis(0, 10, 1);
NumberAxis yAxis = new NumberAxis(0, 10, 1);
final StackedAreaChart<Number,Number> chart = new StackedAreaChart<>(xAxis,yAxis);
chart.setLegendVisible(false);
chart.setCreateSymbols(false);
chart.setAnimated(false);
chart.setOnMouseClicked((MouseEvent event) -> {
clickCount++;
chart.getData().clear();
for(int i=0; i<10; i++){
chart.getData().add(flatSeries());
}
primaryStage.setTitle("After " + clickCount + " clicks.");
});
StackPane root = new StackPane();
root.getChildren().add(chart);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.setTitle("Click the window.");
primaryStage.show();
}
private Series<Number,Number> flatSeries(){
Series<Number,Number> s = new Series<>();
ObservableList<XYChart.Data<Number, Number>> d = s.getData();
d.add(new XYChart.Data<>(0, 1));
d.add(new XYChart.Data<>(10, 1));
return s;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Workaround found:
Insert
while(chart.getData().size() % 8 != 0){
final XYChart.Series<Number,Number> series = new XYChart.Series<>();
series.getData().add(new XYChart.Data<>(0,0));
chart.getData().add(series);
}
before chart.getData().clear();.
StackedAreaChart seems to continue the numbering where it left off, except, strangely, for the first 8 colors.
I am calculating histogram of red component of the image and stored it in redhisto[]. The index of the array represent the intensity(0 to 255)
and the value represent the number of pixel with that intensity. Then plotting those values with JFreeChart.
My question is:
How to make X-axis value start from 0. Now its starting from negative number.
Can we change the color of the bars in the graph
code is :
public class Histogram extends ApplicationFrame {
public Histogram(final String title) throws IOException {
super(title);
IntervalXYDataset dataset = createDataset();
JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
private IntervalXYDataset createDataset() throws IOException {
BufferedImage imageA = ImageIO.read(new File("XYZ.bmp"));
int[] red = new int[imageA.getHeight()*imageA.getWidth()];
int[] redhisto = new int[256];
int[] pixel;
int k= 0;
for (int y = 0; y < imageA.getHeight(); y++) {
for (int x = 0; x < imageA.getWidth(); x++) {
pixel = imageA.getRaster().getPixel(x, y, new int[3]);
red[k] = pixel[0];
k++;
}
}
for(int x=0;x<red.length;x++){
int y = red[x];
redhisto[y]++;
}
final XYSeries series = new XYSeries("No of pixels");
for(int i=0; i<redhisto.length;i++)
series.add(i,redhisto[i]);
final XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
private JFreeChart createChart(IntervalXYDataset dataset) {
final JFreeChart chart = ChartFactory.createXYBarChart("Color Intensity Histogram","X",false,"Y",dataset,PlotOrientation.VERTICAL,true,true,false);
XYPlot plot = (XYPlot) chart.getPlot();
return chart;
}
public static void main(final String[] args) throws IOException {
final Histogram demo = new Histogram("Image Histogram");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
You can change the lower bound of the domain axis and set the series paint as shown below. The default XYBarPainter has a gradient color highlight, so I used a StandardXYBarPainter.
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis axis = plot.getDomainAxis();
axis.setLowerBound(0);
XYBarRenderer r = (XYBarRenderer) plot.getRenderer();
r.setBarPainter(new StandardXYBarPainter());
r.setSeriesPaint(0, Color.blue);
XYPlot plot = (XYPlot) chart.getPlot();
//To change the lower bound of X-axis
NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
xAxis.setLowerBound(0);
//To change the lower bound of Y-axis
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
yAxis.setLowerBound(0);
// To change the color
XYItemRenderer renderer = plot.getRenderer();
renderer.setSeriesPaint(0, Color.green);
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;
}