I want to create a chart that consists of couples of two bars.
one of them a regular bar, the second one is layered and has a deviation.
This is a snippet of my code:
private static JFreeChart createStatisticalBarChart(DefaultStatisticalCategoryDataset dataset, String chartTitle, String domainAxisLabel, String rangeAxisLabel, List<String> sunndayMap) {
CategoryAxis xAxis = new CategoryAxis(domainAxisLabel);
ValueAxis yAxis = new NumberAxis(rangeAxisLabel);
CategoryItemRenderer renderer = new StatisticalBarRenderer();
CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
JFreeChart chart = new JFreeChart(chartTitle,
new Font("Arial", Font.PLAIN, 10),
plot,
true);
My dataset has mean+standarddeviatin records with every second record's deviation being "0", so that no range indicators will be displayed.
How can I accomplish that?
You can use a small negative value in setItemMargin() to achieve an overlap, for example
renderer.setItemMargin(-0.10f);
It appears that standard deviation lines are not drawn if the getStdDevValue() method returns null. You might try that value instead of "0".
Related
I was wondering if it is possible to plot (XYPlot) a dataset in JFreeChart where the series contained in the dataset are plotted against separate y-axis ranges. The date is clustered by category/timestamp, e.g. if my dataset was this:
Timestamp Val1 Val2
2019-04-26 0.6 603
2019-04-25 2.1 1040
2019-04-24 4.1 255
It is impractical to plot both value series on the same range axis.
I've attempted extracting each series into its own dataset, so that I can call plot.mapDataSetToRangeAxis(); but when I add multiple datasets to the plot, the bars tend to render on top of each other. Perhaps I'm missing something simple?
There are a few posts that address separate elements of what I'm looking for, but think I need something that combines these two:
JFreeChart - XYBarChart Show Separate Bars for Each Series
Setting different y-axis for two series with JFreeChart
Here is the python code I'm currently using—inside inductive automation/ignition's reporting module; they allow you configure the JFreeChart prior to rendering.
def configureChart(chart):
from org.jfree.chart.axis import DateAxis
from org.jfree.data.xy import XYSeries, XYSeriesCollection
from org.jfree.chart.renderer.xy import ClusteredXYBarRenderer
from java.awt import Color
from java.text import NumberFormat
class mins_to_str(NumberFormat):
def format(self,*args,**kwargs):
r = ''
number = args[0]
hrs = number//60
mins = number%60
r = '%02i:%02i' %(hrs,mins)
if len(args)>1:
toAppendTo = args[1]
pos = args[2].getField()
r = toAppendTo.insert(pos,r)
return r
plt = chart.getPlot()
renderer = ClusteredXYBarRenderer
xax = DateAxis()
plt.setDomainAxis(xax)
for i in range(plt.getDatasetCount()):
d = plt.getDataset(i)
dsc = XYSeriesCollection()
series = XYSeries(d.getSeriesKey(0))
print('SERIES [%s]' %series)
for r in range(d.getItemCount(0)):
xv = d.getXValue(0,r)
yv = d.getYValue(0,r)
print(' X: %s (%s)' %(xv,type(xv)))
print(' Y: %s (%s)' %(yv,type(yv)))
series.add(xv,yv)
dsc.addSeries(series)
plt.setDataset(i,dsc) # assuming all of my series need to be in the same dsc for this to work...
plt.setRenderer(i,renderer)
if i > 0:
plt.mapDatasetToRangeAxis(i,1)
else:
plt.mapDatasetToRangeAxis(i,0)
plt.getRangeAxis(0).setNumberFormatOverride(mins_to_str())
Currently, I'm getting this:
Any ideas/help would be greatly appreciated.
Here is a time series chart within ignition's Report developing environment.
This one is completely setup using the Chart Options and just a tiny bit of JFreeChart scripting. Should be similar to designing a bar chart. Hope it helps.
JFreeChart Script -
#Import Java classes - Color & JFreeChart
from java.awt import Color
from org.jfree.chart.plot import CategoryPlot
#get Plot of Current Chart
plot = chart.getPlot()
#Set color of domain and range gridlines
plot.setDomainGridlinePaint(Color.black)
plot.setRangeGridlinePaint(Color.black)
I'm developing an app that displays daily financial data, and have chosen to use JFreeChart. I was able to learn how to create a candlestick chart, but my problem lies in customization.
You see, what I'm aiming for is more along the lines of
While, so far all I've been able to manage is
.
No matter how far I zoom in, the candlesticks do not increase in width.
I'm fairly certain that somehow the thin candlesticks have something to do with being bound to a certain time range.. I've tried to remedy that but am not sure what I'm doing wrong here.
SSCE
public void showStockHistory(OHLCDataset dataset, String stockName) {
JFreeChart candleChart = ChartFactory.createCandlestickChart("History of " + stockName, "Date", "Stock Points", dataset, true);
XYPlot plot = candleChart.getXYPlot();
plot.setDomainPannable(true);
plot.setRangePannable(true);
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
NumberAxis range = (NumberAxis)plot.getRangeAxis();
range.setUpperMargin(0.0D);
range.setLowerMargin(0.0D);
range.setAutoRange(true);
range.setAutoRangeIncludesZero(false);
ChartPanel chartPanel = new ChartPanel(candleChart);
chartPanel.setMouseWheelEnabled(true);
chartPanel.setMouseZoomable(true);
getViewport().add(chartPanel);
}
Although my given example seems to have to no differing method calls from the demo in the first picture's code above, it nevertheless only shows thin candlesticks. I assume this to be some kind of bug.
However, I was able to rectify the issue as follows:
getting the renderer for the chart,
casting it to a type of CandlestickRenderer, and
setting its setAutoWidthMethod() method to CandlestickRenderer.WIDTHMETHOD_SMALLEST.
This is how you do it:
JFreeChart candleChart = ChartFactory.createCandlestickChart(
"History of " + stockName, "Date", "Stock Points", dataset, true);
XYPlot plot = candleChart.getXYPlot();
CandlestickRenderer renderer = (CandlestickRenderer) plot.getRenderer();
renderer.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_SMALLEST);
I'm creating an XYSeries in JFreeChart 1.0.17 as shown below, and building a chart out of it dynamically. The x, y data that are added can be of any magnitude, but when the x and y values are very small fractions -- 1e-5 or less -- the autorange calculations seem not to work, and the plot produced will be just a flat line. In this case multiplying all the data by a factor of 10,000 before adding them to the series leads to a correct plot. The data are added as doubles, and I've looked at the XYSeries object in a debugger to make sure the correct values are ending up there. Am I missing something? Is there some way to help the autorange calculations do the right thing?
series = new XYSeries("Heartbeat");
final XYSeriesCollection data = new XYSeriesCollection(series);
chart = ChartFactory.createXYLineChart("", "", "", data, PlotOrientation.VERTICAL, false, true, false);
final XYPlot plot = chart.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
((NumberAxis) domain).setAutoRangeIncludesZero(false);
ValueAxis range = plot.getRangeAxis();
range.setAutoRange(true);
((NumberAxis) range).setAutoRangeIncludesZero(false);
The ValueAxis class has an autoRangeMinimumSize attribute which defaults to 0.00000001. When the range is automatically calculated, the axis won't let it go below this size. It is intended for the case where all your data values are the same, in which case it determines the axis length. But as you've found, it causes problems if all your data values are less than 0.00000001, so you should set it to something lower instead of using the default.
I am trying to do a ValueAxis with different intervals. I mean, for example, I want to do a jfrechart with a valueAxis that I can see only the number 1,5,7. I have tried that with the next code but I get a valueAxis with a one fix interval.
CategoryPlot categoryplot = (CategoryPlot) jfreechart.getPlot();
ValueAxis valueaxis = categoryplot.getRangeAxis();
TickUnits units = new TickUnits();
units.add(new NumberTickUnit(1));
units.add(new NumberTickUnit(5));
units.add(new NumberTickUnit(7));
valueaxis.setStandardTickUnits(units);
Does anyone know how I have to do?. Thanks.
I have a TimeSeries Chart with a XYdataset which has the milliseconds of each dates.
Now I want to have a chart that only displays each date one time on the axis, no matter what the range of dates is. I already got it so far, that only the date is printed, not the time (via setNumberFormatOverride() method).
What I have now, is this:
alt text http://dl.getdropbox.com/u/1144075/Bildschirmfoto%202010-08-05%20um%2016.51.39.JPG
What I want, is this:
alt text http://dl.getdropbox.com/u/1144075/Bildschirmfoto%202010-08-05%20um%2016.54.54.JPG
This is a snippet of my code. also, the setLabelAngle() method don't work?!
JFreeChart chart = ChartFactory.createTimeSeriesChart(...);
XYPlot xyplot = (XYPlot)chart.getPlot();
DateAxis dateaxis = (DateAxis) xyplot.getDomainAxis();
dateaxis.setLabelAngle(Math.PI / 6.0);`
numberaxis.setNumberFormatOverride((DecimalFormat)DecimalFormat.getInstance(Locale.GERMAN));
You can set the TickUnit to any convenient DateTickUnitType. I use DAY in this example and MMM to verify the Locale:
axis.setTickUnit(new DateTickUnit(DateTickUnitType.DAY, 1,
new SimpleDateFormat("dd.MMM.yy", Locale.GERMAN)));
As you are a returning customer, I'll address the second question, too: setLabelAngle() works perfectly well, but it changes the axis label in the chart legend. Using setVerticalTickLabels() is an alternative for the tick labels themselves:
axis.setVerticalTickLabels(true);