Resize an axis fitting another with JFreechart - java

i'm trying to make an overlaid plot,
And my problem is that i can't bring the second plot to fit the second one.
Here is my first plot :
And here the second one :
And when i try to fit both, here is what i get :
So basically, i would like to fit the whole second plot between 0 and 30, how can i do this without losing any data?
First I tried using plot.mapDatasetToRangeAxis()
Then i tried with :
domain.setRange(0.00, 30.0);
domain.setTickUnit(new NumberTickUnit(1));
But i couldn't bring neither the first, nor the second one to work as i wish.
Do you have any other ideas? (except buying this - which i can't afford right now as a student).
Any help will be greatly appreciated :)
Oh and by the way the x-axis is a speed (forgot to draw it on the plot).
So here a very ugly photomontage of the kind of result i wish to have (with fitting units on the x and y axis) :
Sorry for my Gimp skills, which are beyond bad.
Here is what i did :
private JFreeChart createOverlaidChart()
{
final NumberAxis domainAxis = new NumberAxis("Speed (m / s)");
final ValueAxis rangeAxis = new NumberAxis("Power (kw)");
// create plot ...
final IntervalXYDataset data0 = createDataset0();
final XYItemRenderer renderer0 = new XYBarRenderer(0.20);
// change "new XYBarRenderer(0.20)" to "StandardXYItemRenderer()" if you want to change type of graph
final XYPlot plot = new XYPlot(data0, domainAxis, rangeAxis, renderer0);
// add a second dataset and renderer...
final IntervalXYDataset data1 = createDataset1();
final XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer(false, true);
// arguments of new XYLineAndShapeRenderer are to activate or deactivate the display of points or line. Set first argument to true if you want to draw lines between the points for e.g.
plot.setDataset(1, data1);
plot.setRenderer(1, renderer1);
// add a third dataset and renderer...
final IntervalXYDataset data2 = createDataset2();
final XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer(true, true);
// arguments of new XYLineAndShapeRenderer are to activate or deactivate the display of points or line. Set first argument to true if you want to draw lines between the points for e.g.
plot.setDataset(2, data2);
plot.setRenderer(2, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
// return a new chart containing the overlaid plot...
return new JFreeChart("Test", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}

The Range Axis is the Vertical/Y Axis, you need to add a second Domain Axis (Horizontal/X Axis) to your chart.

I did something similar -- although using same X axis vales but differing Y axis. For this, I use single Domain (you'd want single Range). I convert for you (there may be typos due to my edits):
priceXYPlot.setRangeAxis( new new NumberAxis( "Y" ) );
priceXYPlot.setDomainAxis( 0, new NumberAxis( "X1" ) );
priceXYPlot.setDomainAxis( 1, new NumberAxis("X2") );
and mapDatasetToRangeAxis so that you had two diff X axis along top & bottom, something like:
priceXYPlot.setDataset( 0, data0);
priceXYPlot.mapDatasetToDomainAxis( 0, 0 ); //1st dataset to 1st x-axis
priceXYPlot.setDataset( 1, data1 );
priceXYPlot.mapDatasetToDomainAxis( 1, 1 ); //2nd dataset to 2nd x-axis

Related

Forcing a specific number and set of domain axis labels in Java JFreeChart

I'm trying to write a method to create a simple graph of a normal distribution in JFreeChart and save it as a file. Here's an example of an output image that's pretty much exactly what I want
Notice that there are exactly 9 tick marks on the x axis. The center one is the mean of the distribution, and the rest of the ticks indicate standard deviations. There is one tick for each standard deviation from the mean.
Here's an example of another chart showing a normal distribution with a mean of 7 and a standard deviation of 5 and no other code changes.
This is not what I want. Suddenly there are only 8 tick marks, and there is no tick in the center to mark the mean. It appears that JFreeChart wants to only use nice round numbers instead of the odd 7 as the center tick.
I've tried reading other StackOverflow questions on forcing axis labels, but it appears everyone else wants to do this with some form of dates. It would help if I could simply specify 9 exactly values to put on the axis instead of them being autogenerated, but I don't know how to do that.
There's also one other problem. If you look at the curve near the sides of the graph, it is clipping below the frame of the plot and running into the tick marks. I want to add padding between the curve and the tick marks. I tried using something like plot.getRangeAxis().setRange(-0.01, 0.09); but I ran into a bizarre problem where it appears that the height of the normal distribution is impacted by its width. Large means and standard deviations cause this to break miserably. (That makes zero sense from a statistics standpoint and I'm starting to question this normal distribution method.)
Anyway I basically need a way to force the chart to (a) add padding around the curve and (b) use exactly nine tick marks corresponding to the mean and four standard deviations out.
Here's my current code, which was mostly stolen online and trimmed to what appeared to be actually necessary:
static double mean = 7.0, sd = 5.0;
static Color line = new Color(0x6AA2A3);
static Color grey = new Color(0x555555);
public static void main(String[] args) throws IOException {
// Create the normal distribution
double minX = mean - (4 * sd), maxX = mean + (4 * sd);
Function2D normal = new NormalDistributionFunction2D(mean, sd);
XYDataset dataset = DatasetUtils.sampleFunction2D(normal, minX, maxX, 100, "Normal");
JFreeChart chart = ChartFactory.createXYLineChart(null, null, null, dataset, PlotOrientation.VERTICAL, false, false, false);
chart.setBorderVisible(true);
// Create and format the Plot
XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.getRangeAxis().setVisible(false);
plot.setOutlineVisible(false);
// Format the X axis to look pretty
NumberAxis domain = (NumberAxis) plot.getDomainAxis();
domain.setRange(minX, maxX);
domain.setAxisLineVisible(false);
domain.setAutoRangeStickyZero(false);
domain.setTickUnit(new NumberTickUnit(sd));
domain.setTickLabelFont(new Font("Roboto", Font.PLAIN, 20));
domain.setTickLabelPaint(grey);
domain.setTickMarkStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
domain.setTickMarkInsideLength(8);
domain.setTickMarkPaint(grey);
// Create a renderer to turn the chart into an image
XYLineAndShapeRenderer render = (XYLineAndShapeRenderer) plot.getRenderer(0);
render.setSeriesStroke(0, new BasicStroke(4));
render.setSeriesPaint(0, line);
// Output the final image
chart.setPadding(new RectangleInsets(5, 20, 20, 20));
BufferedImage image = chart.createBufferedImage(600,400);
File outFile = new File("graph.png");
outFile.createNewFile();
ImageIO.write(image, "png", outFile);
}
for request a),
plot.setAxisOffset(new RectangleInsets(5,5,5,5));
should do the trick.
For request b), the general recommendation is to override
refreshTicks(Graphics2D g2, AxisState state,Rectangle2D dataArea,RectangleEdge edge)
of the
ValueAxis
class and return a suitable List of ticks. Though doing so may look a bit intimidating, it is not if your logic is simple. You could try to simply add a NumberTick for the mean to the auto-generated tick list.

JFreeChart - Not fully visible line chart

I am using JFreeChart library to create Chart on website (library integrated with my application according to this tutorial). Everything looks great except one thing: for some reason, for some data line chart is not completly visible (please see screen).
I don't know why is it happening. I'm posting code responsible for configuration:
public JFreeChart createChart()
{
NumberAxis numberaxis = new NumberAxis("X");
numberaxis.setAutoRangeIncludesZero(false);
NumberAxis numberaxis1 = new NumberAxis("Y");
numberaxis1.setAutoRangeIncludesZero(false);
XYSplineRenderer xysplinerenderer = new XYSplineRenderer();
XYPlot xyplot = new XYPlot(createSampleData(), numberaxis, numberaxis1, xysplinerenderer);
xyplot.setBackgroundPaint(new Color(238, 242, 250));//
xyplot.setDomainGridlinePaint(new Color(238, 242, 250));
xyplot.setRangeGridlinePaint(new Color(238, 242, 250));
xyplot.getRenderer().setSeriesPaint(0, Color.BLUE);
xyplot.setAxisOffset(new RectangleInsets(4D, 4D, 4D, 4D));
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) xyplot.getRenderer();
renderer.setSeriesShapesVisible(0, true);//FIXME Dots
xyplot.getDomainAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits());
JFreeChart jfreechart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, xyplot, true);
jfreechart.setBackgroundPaint(Color.white);
return jfreechart;
}
The link provided by Richard describes the problem well; but, ultimately, it looks like you need to manually set the upper bound of your range axis to account for the upper curve of the spline produced by XYSplineRenderer. For your example above, this might be:
xyplot.getRangeAxis().setUpperBound(22.5);
For practical purposes, you would probably want to calculate the maximum Y value, and either add a percentage to it, or more complicated, calculate a ceiling based on its surrounding points. I would start by adding 10% and see how that goes:
// Iterate data values; use Math.max() to determine maxYValue; then:
xyplot.getRangeAxis().setUpperBound( maxYValue + maxYValue * 0.1);
It's at patch, but it should provide the result you want, depending on the nature of your data and the curves produced connecting data points.

JFreeChart: How to plot a line graph and a scatter on same chart

i have two sets of data
int[] x1 = {1,2,3,4,5,6,7,8,9,10};
int[] y1 = {1,2,3,5,6,8,9,10,14,11};
int[] x2 = {1,2,3,4,5,6,7,8,9,10};
int[] y2 = {0,2,3,5,0,8,9,8,14,11};
int[] z2 = {1,2,3,1,2,3,1,2,3,1};
I want to plot the x1,y1 as an XYLineChart and then plot x2,y2 as a scatter on the same plot without a line.
I also need each scatter point of xy,y2 to be a different color depending on the value of z2 (1=Color.red, 2=Color.green, 3=Color.blue)
How can i do this?
So far i have:
JPanel panel_1 = new JPanel();
panel_1.setLayout(new BorderLayout(0, 0));
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series1 = new XYSeries("series1");
for(int i=0; i<x1.length; i++){
series1.add(x1[i],y1[i]);
}
dataset.add(series1);
JFreeChart chart = ChartFactory.createXYLineChart("Title", "x", "y", dataset, PlotOrientation.VERTICAL, false, false, false);
ChartPanel cp = new ChartPanel(chart);
panel_1.add(cp, BorderLayout.CENTER);
This gets the line graph sorted. I now need to code the scatter plot for x2,y2 (with colors described above) which is where im stuck.
The createXYLineChart() method will create a chart that uses an XYLineAndShapeRenderer. So fetch the renderer from the plot and cast it to XYLineAndShapeRenderer. Then you can call the methods setSeriesLinesVisible() and setSeriesShapesVisible() to control, for each series, whether shapes and/or lines are drawn for the data items. That way you can use a single renderer and dataset, which makes things simpler.
Your requirement to change the colors depending on another data value requires a little more work. You should subclass the XYLineAndShapeRenderer class and override the getItemPaint(int, int) method. Here you can return any color you want for a data item. The default implementation looks at the series index and returns the color for the series. You need to look at the item index as well, then do a lookup in your table of z-values and decide what color to return.

Different color for different series in XYline chart JFreeChart

I have created XY line chart using JFreeChart, having two datasets, I want both the lines to be in different colors. I tried using following code-
XYPlot plot = chart.getXYPlot();
XYItemRenderer xyir = plot.getRenderer();
xyir.setSeriesPaint(0, Color.GREEN);
plot.setDataset(0, xyDataset1);
xyir.setSeriesPaint(1, Color.blue);
plot.setDataset(1, xyDataset2);
Also I have tried using following code, where I am using different renderer (don't know whether this is correct way to do it)-
XYPlot plot1 = chart.getXYPlot();
XYPlot plot2 = chart.getXYPlot();
XYItemRenderer xyir1 = plot1.getRenderer();
xyir1.setSeriesPaint(0, Color.GREEN);
plot1.setDataset(0, xyDataset1);
XYItemRenderer xyir2 = plot2.getRenderer();
xyir2.setSeriesPaint(1, Color.blue);
plot2.setDataset(1, xyDataset2);
In both the cases its printing both the lines in blue color.
What's wrong?? Any suggestions??
Found the solution, it works for me, using two different Renderer, earlier i was not doing it properly--
XYPlot plot = chart.getXYPlot();
plot.setDataset(0, xyDataset1);
plot.setDataset(1, xyDataset2);
XYLineAndShapeRenderer renderer0 = new XYLineAndShapeRenderer();
XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer();
plot.setRenderer(0, renderer0);
plot.setRenderer(1, renderer1);
plot.getRendererForDataset(plot.getDataset(0)).setSeriesPaint(0, Color.red);
plot.getRendererForDataset(plot.getDataset(1)).setSeriesPaint(0, Color.blue);
The approach shown works in this example, and a single renderer should be sufficient. An sscce may help isolate the problem.
To control individual items, you can override getItemPaint(), shown here.
Try to set the Series paint to null in the renderer setSeriesPaint(null);
If you take a look at the source it first checks to see if the paint is !null, then uses the base color.
If null it uses the colors associated with the time serie from a lookup table.

JFreeChart to represent 3D data in a 2D graph using colourmaps

I'm currently trying to use JFreeChart to represent 3D data in a 2D graph.
Essentially, I have a 2d array called data[i][j]. The i and j represent the y and x coordinates where I want to plot. The value of data[i][j] represents a frequency value, which I want to represent in the graph as a colour.
I'm not entirely sure what something like this is called, but it would look something like this:
Now I have been trying to do this using XYBlockRenderer, however I am having issues with defining the dataset. I am trying to use DefaultXYZDataset, but I'm really confused at how to even define the data here.
Can someone explain how to use the DefaultXYZDataset to accomplish such a task?
DefaultXYZDataset dataset = new DefaultXYZDataset();
Concentration.dataoutHeight = Concentration.dataout[0].length;
System.out.println(Concentration.dataoutHeight);
System.out.println(ImageProcessor.MAXCBVINT);
double[][] data = new double[3][ImageProcessor.MAXCBVINT];
for (int i = 0; i < Concentration.dataoutHeight; i++) {
for (int j = 0; j < ImageProcessor.MAXCBVINT; j++) {
data[0][j] = j;//x value
data[1][j] = i;//y value
data[2][j] = Concentration.dataout[j][i][0];//Colour
}
dataset.addSeries(i, data);
}
NumberAxis xAxis = new NumberAxis("Intensity");
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
NumberAxis yAxis = new NumberAxis("Distance to Closest Blood Vessel (um)");
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setLowerMargin(0.0);
yAxis.setUpperMargin(0.0);
XYBlockRenderer renderer = new XYBlockRenderer();
PaintScale scale = new GrayPaintScale(0, 10000.0);
renderer.setPaintScale(scale);
renderer.setBlockHeight(1);
renderer.setBlockWidth(1);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinesVisible(false);
plot.setRangeGridlinePaint(Color.white);
JFreeChart chart = new JFreeChart("Surface Plot", plot);
chart.removeLegend();
chart.setBackgroundPaint(Color.white);
ChartFrame frame = new ChartFrame("Surface Map - "
+ (Concentration.testing ? "TESTING using "
+ Concentration.testfile : currentFile.getName()), chart);
frame.pack();
frame.setVisible(true);
You have two options:
Represent them as 3d
3D Lib for JFreeChart
You need to use the class : XYBlockRenderer which does exactly what you are asking. You can download the JFreeChart demo collection where the code for this is given.
(source code of class here)
There is also this full code example with 4D very similar.

Categories