I am creating a graph with contain x and y value. The y axis in normal but x is with the logarithmic value. I used the library (jfreechart.jar) for making this logarithmic graph.
My question is how can in fine the exact value of x if for example y is 10? (the value of x is in logarithmic number)
private void interActionPerformed(java.awt.event.ActionEvent evt) {
final XYSeries s1 = new XYSeries("Series 1");
s1.add(0.075,4.8);
s1.add(0.15,13.9);
s1.add(0.425,19.5);
s1.add(0.6,22.1);
s1.add(1.18,26.6);
s1.add(2,29.5);
s1.add(2.36,31.2);
s1.add(4.75,38.6);
s1.add(9.5,46.2);
s1.add(19,62.4);
s1.add(25,76.);
s1.add(37.5,86.2);
s1.add(50,100);
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(s1);
final JFreeChart chart = ChartFactory.createXYLineChart(
"sieve analyese", // chart title
"sieve size", // domain axis label
"passing", // range axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true,
false
);
final XYPlot plot = chart.getXYPlot();
final LogarithmicAxis domainAxis = new LogarithmicAxis("particle size in milimeters");
final NumberAxis rangeAxis = new NumberAxis("percent passing");
plot.setDomainAxis(domainAxis);
plot.setRangeAxis(rangeAxis);
BarRenderer renderer = null;
ChartFrame frame = new ChartFrame("sive chart", chart);
frame.setVisible(true);
frame.setSize(1000,600);
chart.setBackgroundPaint(Color.lightGray);
plot.setOutlinePaint(Color.RED);
} [chart of x and y value][1]
Use the below function to get the value of x from y
x = Math.log(y)
For exact value of X you should know exact dependence (function) of Y(X) or X(Y). For real-life data the kind of this function often is unknown, and one have to apply some approximation method.
Considering that your data are monotone (increasing), you can find an index of interval where given Y lie using binary search. For sample data you'll find 0-th interval between (0.075,4.8) and (0.15,13.9)
Then apply some interpolation method. The simplest approach - linear interpolation.
For you data set you might use quadratic interpolation with better accuracy - use 3 closest points to build parabola equation, and from this equation get X for given Y.
Related
I'm using an XYBoxAnnotation to demarcate a rectangular area on a JFreeChart. I would like one side of the box to be "open", i.e go out to infinity. I tried setting the value to Double.POSITIVE_INFINITY but this did not seem to work. I also tried setting it to Double.MAX_VALUE, with no luck either. In these cases, the annotation doesn't even show up on the plot at all. And there are no exceptions thrown.
Below is a very simple version of my code in which I generate the XYBoxAnnotation and add it to the plot.
XYBoxAnnotation _axisMarker = new XYBoxAnnotation(xLow, yLow, Double.POSITIVE_INFINITY, yHigh, new BasicStroke(0.5F), Color.WHITE, Color.WHITE);
_plot.getRenderer().addAnnotation(_axisMarker, Layer.BACKGROUND);
EDIT:
I figured out that the reason the annotation wasn't showing up was because the x value for the annotation was much much larger than the axis scale. For some reason, this causes the annotation to not be visible until you zoom out enough.
Thanks to #trashgod's answer below, I came up with a solution. His answer didn't quite work for me since my plot allows zooming and you could see the edge of the box when you zoomed out.
First, I added a PlotChangeListener to listen for when the plot is zoomed:
// define PlotChangeListener to update the annotation when the plot is zoomed
private PlotChangeListener _zoomListener = new PlotChangeListener() {
#Override
public void plotChanged(PlotChangeEvent plotChangeEvent) {
if (_basisIsotope != null) {
updateAxisMarkers();
}
}
};
Then I created a function to re-draw the annotation based on the new plot bounds:
// function to re-draw the annotation
private void updateAxisMarkers() {
_plot.removeChangeListener(_zoomListener); // remove to prevent triggering infinite loop
// define xLow, yLow and yHigh...
double xHigh = _plot.getDomainAxis().getUpperBound() * 1.1;
XYBoxAnnotation _axisMarker = new = new XYBoxAnnotation(xLow, yLow, xHigh, yHigh, new BasicStroke(0.5F), Color.WHITE, Color.WHITE);
_plot.getRenderer().addAnnotation(annotation);
_plot.addChangeListener(_zoomListener); // add back
}
Double.MAX_VALUE is too large to scale to the relevant axis, but Double.MAX_VALUE / 2 works as well as any value larger than the upper bound of the axis. A better choice might be a value that exceeds the maximum value of the domain by some margin. The fragment below shades a plot of some Gaussian data with an XYBoxAnnotation that has domain bounds extending from 42 to the maximum domain value + 10%; the range bounds are ±1σ.
XYSeriesCollection dataset = createDataset();
JFreeChart chart = createChart(dataset);
Color color = new Color(0, 0, 255, 63);
double max = dataset.getSeries(0).getMaxX() * 1.1;
XYBoxAnnotation annotation = new XYBoxAnnotation(
42, -1, max, 1, new BasicStroke(1f), color, color);
chart.getXYPlot().getRenderer().addAnnotation(annotation);
I am new to JFreeChart. My requirement is to display the X axis (time-axis) as following (time ranges will be configurable as per user input) for a line chart with suppose 3 variables:
3rdAug-8thAug..10thAug-15thAug.. [ and so on ]
Currently my graph's X axis is like this :
1..2..3..4..5 ..
[Unable to attach screenshots]
My demo code is as follows :
private JFreeChart createChart(final XYDataset dataset) {
// create the chart...
final JFreeChart chart = ChartFactory.createXYLineChart(
"Line Chart Demo ", // chart title
"X", // x axis label
"Y", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
// OPTIONAL CUSTOMISATION OF THE CHART...
chart.setBackgroundPaint(Color.white);
// get a reference to the plot for further customisation...
final XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
renderer.setSeriesLinesVisible(0, true); //for line visibility
renderer.setSeriesShapesVisible(1, false);
plot.setRenderer(renderer);
// change the auto tick unit selection to integer units only...
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
// final Axis range = plot.get
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// OPTIONAL CUSTOMISATION COMPLETED.
return chart;
}
Can anyone point me in the right direction here?
How do I get only the required values shown on the X axis?
XYPlot differ between domain axes and range axes. In your case the X axis is the domain axis whereas the Y axis is the range axis.
Valuexis domainAxis = plot.getDomainAxis();
You can also set a different domain axis:
ValueAxis dAxis = new ...
plot.setDomainAxis(dAxis);
You want to use JFreeChart's TimeLine interface to limit the shown dates on the DateAxis (which is actually the domain-axis in your case, as already pointed out by #Uli). For your requirement the default implementation SegmentedTimeline should fulfill your requirements. Just configure it and pass it on to your axis:
SegmentedTimeline timeline = new SegmentedTimeline(
86400000l, // segment size = one day in ms (24*3600*1000)
5, // include 5 segments (days)
2); // exclude 2 segments (days)
DateAxis axis = new DateAxis();
axis.setTimeline(timeline);
And don't forget to configure the plot to use the new DateAxis, as XYPlot uses NumberAxis by default:
plot.setDomainAxis(axis);
hth,
- martin
I need to set minimum X-tick interval in the chart. I have a dataset that contains 1000 entries, i.e. <0,12>,<5,22>,<10,23>,...,<1000,20>. In dataset, the interval between X-values is equal to 5. In the chart I want to set X-tick interval equal to 100.
I use this code, but it does not work:
NumberAxis range = (NumberAxis)plot.getRangeAxis();
range.setTickUnit(new NumberTickUnit(100));
Here is my code snippet:
private JFreeChart createChart(CategoryDataset dataset)
{
final JFreeChart chart = ChartFactory.createAreaChart(
this.title,
"Time",
"Net demand",
dataset,
PlotOrientation.VERTICAL,
true,
true,
false
);
Title t = new TextTitle(this.subtitle);
chart.addSubtitle(t);
int transparency = 95;
Color c = new Color(1, 158, 115, transparency);
final CategoryPlot plot = chart.getCategoryPlot();
CategoryItemRenderer renderer = new CustomRenderer(c);
renderer.setSeriesOutlinePaint(0, Color.black);
renderer.setSeriesOutlineStroke(0, new BasicStroke(0.5f));
renderer.setSeriesPaint(0,c);
plot.setRenderer(renderer);
NumberAxis range = (NumberAxis)plot.getRangeAxis();
range.setTickUnit(new NumberTickUnit(60));
return chart;
}
You've set the tick unit for the range axis, which is the y-axis in JFreeChart. For the x-axis, you want the domain axis.
NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
xAxis.setTickUnit(new NumberTickUnit(60));
The domain and range terms come from a function mapping a set of domain values to a set of range values. With hindsight, using getXAxis() and getYAxis() for the method names would have been clearer for most people...for JFreeChart 2 I'll probably change it.
I'm building multiple stacked bar charts (subplots) that are combined through a CombinedRangeCategoryPlot.
As the subplots datasets do not have the same number of items and since JFreeChart decides to allocate the same space for each subplot, I have different widths of bars.
Is there any way I can align their width (even if it means that the subplots have different widths)?
Please see below for the result and the code I have so far.
Many thanks,
Thomas
//Builds commong range axis
NumberAxis rangeAxis = new NumberAxis("%");
rangeAxis.setRange(0, 1.0);
rangeAxis.setNumberFormatOverride(NumberFormat.getPercentInstance());
//Builds common data set
CombinedRangeCategoryPlot combinedPlots = new CombinedRangeCategoryPlot(rangeAxis);
for (int groupIndex=0; groupIndex<LeakGroups.values().length; ++groupIndex){
//Builds category axis
CategoryAxis categoryAxis = new CategoryAxis(GuiConstants.LEAK_GROUPS_LABELS[groupIndex]);
//Sets margins between bars
categoryAxis.setCategoryMargin(0.5f);
//Builds bar renderer
StackedBarRenderer barRenderer = new StackedBarRenderer();
barRenderer.setRenderAsPercentages(true);
//Builds dot/level renderer
LineAndShapeRenderer dotRenderer = new LineAndShapeRenderer();
//dotRenderer.setSeriesLinesVisible(0, false);
//dotRenderer.setSeriesShapesVisible(0, false);
//dotRenderer.setSeriesLinesVisible(1, false);
//Defines level shape height (depends on chart size): nominal values are for a height of 1000px
int shapeHeightPx = (int) Math.round(20 * (this.getHeight() / 1000.0));
dotRenderer.setSeriesShape(1, new Rectangle(-1, -shapeHeightPx/2, 2, shapeHeightPx));
//Builds plot
CategoryPlot plot = new CategoryPlot();
plot.setDomainAxis(categoryAxis);
plot.setDataset(0, data[groupIndex].bars);
plot.setRenderer(0, barRenderer);
plot.setDataset(1, data[groupIndex].dots);
plot.setRenderer(1, dotRenderer);
//Adds to combined
combinedPlots.add(plot);
}
combinedPlots.setOrientation(PlotOrientation.HORIZONTAL);
//Puts range axis at the bottom
combinedPlots.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
//Changes plot render sequence so that bars are in the background and shapes in front
combinedPlots.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
//Shows gridlines for categories and not for values
combinedPlots.setDomainGridlinesVisible(true);
combinedPlots.setRangeGridlinesVisible(false);
//Creates chart
JFreeChart chart = new JFreeChart("Leaks", combinedPlots);
//Sets a margin right to allow space for last catergory label ("100%")
chart.setPadding(new RectangleInsets(0, 0, 0, 20));
return chart;
For some reason, the weight gets reset to value 1 when adding the plot.
By way of explanation,
The add(CategoryPlot subplot) method specifies a default weight of 1,
The add(CategoryPlot subplot, int weight) method lets you specify a weight value.
After a few hours of search, found the solution: use plot.setWeight().
For some reason, the weight gets reset to value 1 when adding the plot to the CombinedRangeCategoryPlot, hence it has to be set after.
Hope this helps.
I've been googling my for a while now, and did not find any useful stuff, so that is why I ask you guys.
Can I draw mathematical functions (e.g. sine, cosine, etc.) with JFreeChart?
Thanks
JFreeChart is for plotting data, not functions. But you should be able to create a table of (x,y) values and then plot them. If this is for a desktop app, look at the JavaFX api. The API includes charts and functions to draw lines.
Im assuming that you can plot the points yourself in which case you would simply evaluate the mathematical function for each x along the graph.
getY(float x) {
return /*your function*/ Math.sin(x);
}
There may not be a built in way to plot sinx but there doesn't need to be. Remember that what your saying is y=sin(x)! What you need to plot is the x and y value. Create a loop of x values then plug them into sin(x) using Java and Math. That answer IS your y value! So now you have your x and y values to plot sin(x).
Example
final XYSeries series1 = new XYSeries("First");
for(double i = 0; i < 10; i += 0.2){
double sinx = Math.sin(i);
series1.add(i, sinx);
}
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series1);