I am creating a chart using JFreeChart, and I get the following behavior.
Notice the gap between the light and dark shades of pink.
I was just plotting sample data over time, so I don't think it has anything to do with my data. Has anyone encountered this issue before? I am using a stacked XY area chart.
Here is the code to create my dataset:
double sample = 1.0;
TimeTableXYDataset dataset = new TimeTableXYDataset();
List<TimeSeries> timeSeriesList = timeSeriesCollection.getSeries();
for (TimeSeries t : timeSeriesList) {
for (index = 0; index < t.getItemCount(); index++) {
dataset.add(t.getTimePeriod(index), sample, t.getDescription());
}
sample++;
}
Problem fixed. I was overwriting the plot renderer with itself.
Related
I'm been writing maze algorithms, and want to draw the mazes generated using JavaFX.
To begin with, I'm attempting to draw a simple grid - but made up of smaller shapes so that I'll later be able to change the shape of the grid into that of a maze.
I'm using little upper left corner shapes (like ┏) and a GridPane, but this is leading to small discontinuities between the cells. (screenshot and code below). How can I wedge these shapes together seamlessly? Am I barking up the wrong tree with the Gridpane idea?
attempted grid drawing so far
My code, below, is actually written in Scala; I'm using ScalaFX, but finding help for ScalaFX online is a nightmare so I've been going solely off JavaFX docs - they are pretty much the same thing as far as I've gathered.
val lineLength: Int = 30
def makeClosedCell(length: Int = lineLength): Shape = {
val wallN = Line(0,0,length,0)
val wallW = Line(0,0,0,length)
val closedCell: Shape = Shape.union(wallN, wallW)
return closedCell
}
def makeOpenW(length: Int = lineLength): Shape = Line(0,0,length,0)
def makeOpenN(length: Int = lineLength): Shape = Line(0,0,0,length)
def initialiseGrid(r: GridPane, sizex: Int, sizey: Int): Unit = {
for (i <- 0 until sizex) {
val colConst = new ColumnConstraints()
colConst.setPercentWidth(100.0 / sizex)
r.getColumnConstraints().add(colConst)
}
for (i <- 0 until sizey) {
val rowConst = new RowConstraints()
rowConst.setPercentHeight(100.0 / sizey)
r.getRowConstraints().add(rowConst)
}
for(j <- sizey-1 to 0 by -1){
for(i <- 0 until sizex){
r.add(makeClosedCell(),i,j)
}
r.add(makeOpenN(),sizex,j)
}
for(i <- 0 until sizex){
r.add(makeOpenW(),i,sizey)
}
}
Just found a solution. I've found this can be solved by fixing the exact column and row widths and heights to the same value as the line lengths, like so:
val rowConst = new RowConstraints()
// remove: rowConst.setPercentHeight(100.0 / sizey)
rowConst.setMinHeight(length)
rowConst.setMaxHeight(length)
r.getRowConstraints().add(rowConst)
With length passed into the initialisation function, of course.
I have an XSSFSheet with images at the end of my used rows. When adding a new row, I would like to shift all images one row down. I have found this similar question about moving charts, and have tried to use the part of the answer that does the actual moving of the charts, because It looked like it would work for images as well.
java.util.List<CTTwoCellAnchor> drawingAnchors = ((XSSFDrawing)sheet.getDrawingPatriarch()).getCTDrawing().getTwoCellAnchorList();
for (CTTwoCellAnchor drawingAnchor : drawingAnchors) {
int fromRow = drawingAnchor.getFrom().getRow();
int toRow = drawingAnchor.getTo().getRow();
if (fromRow >= startRow) {
drawingAnchor.getFrom().setRow(fromRow + n);
drawingAnchor.getTo().setRow(toRow + n);
}
}
but this did not work but throws a NoClassDefFoundError instead.
(Edit: I now found out that this error can be solved by providing the full jar of all of the schemas ooxml-schemas as mentioned in FAQ-N10025. thanks #Axel Richter)
After trying out several different approaches, I found a way to do it. Since it took me so long, and there is no info about this anywhere yet, I decided to post my findings here on SO.
Please find my solution in my own answer. Cheers
The following code gets the Drawing Patriarch of the sheet, iterates over all it's shapes, and if the shape is of type XSSFPicture it modifies the rowindexes through its XSSFClientAnchor.
int moveRowsBy = 1; // 1 will move the images 1 row down. moveRowsBy can be negative to move up
XSSFDrawing drawing = sheet.getDrawingPatriarch();
for (XSSFShape shape : drawing.getShapes()) {
if (shape instanceof XSSFPicture){
XSSFClientAnchor anchor = ((XSSFPicture)shape).getClientAnchor();
anchor.setRow1(anchor.getRow1() +moveRowsBy);
anchor.setRow2(anchor.getRow2() +moveRowsBy);
// if needed you could change column too, using one of these:
// anchor.setCol1(newColumnInt)
// anchor.setCol1(anchor.getCol1() + moveColsBy)
}
}
I have a plot that I've created with GRAL:
GRAL plot
The problems I'm having are with the axis. Basically I'd like the Y axis to run from 0 .. 4 in every graph, and I can't find a way to force this behaviour. If I zoom out there is extra increments, but I'd like 0 .. 4 show up in the unzoomed plots.
I've also tried using setCustomTicks but the default ticks remain, is there a way to remove them and only use custom ones?
Help would be greatly appreciated!
The code for my plot is:
int[][] seq_data_200 = chunkArray(seq_data, 200);
DataTable[] listData = new DataTable[seq_data_200.length];
for (int i = 0; i < seq_data_200.length; i++){
DataTable data = new DataTable(Integer.class, Integer.class);
for (int j = 0; j < seq_data_200[i].length; j++) {
data.add(j, seq_data_200[i][j]);
}
listData[i] = data;
}
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
panel.setLayout(new GridLayout(seq_data_200.length,1,20,20));
for (int i = 0; i < listData.length; i++) {
XYPlot plot = new XYPlot(listData[i]);
LineRenderer lines = new DefaultLineRenderer2D();
plot.setLineRenderer(listData[i], lines);
Color color = new Color(0.0f, 0.3f, 1.0f);
plot.getPointRenderer(listData[i]).setColor(color);
plot.getLineRenderer(listData[i]).setColor(color);
double insetsTop = 20.0, insetsLeft = 60.0, insetsBottom = 60.0, insetsRight = 40.0;
plot.setInsets(new Insets2D.Double(insetsTop, insetsLeft, insetsBottom, insetsRight));
plot.getTitle().setText(getTitle(i, sequence));
plot.getAxisRenderer(XYPlot.AXIS_X).setLabel("Bases");
plot.getAxisRenderer(XYPlot.AXIS_X).setCustomTicks(getTicks(i, sequence));
plot.getAxisRenderer(XYPlot.AXIS_Y).setLabel("Number of " + nucleo + "'s");
plot.getAxisRenderer(XYPlot.AXIS_Y).setMinorTicksVisible(false);
plot.getAxisRenderer(XYPlot.AXIS_Y).setTickSpacing(1);
panel.add(new InteractivePanel(plot), BorderLayout.CENTER);
}
I found a somewhat hackish fix that works in the interim:
GRAL decides on axis height using the DataTable. It uses the max and min values of the table to define the viewport.
So if you add two pieces of Data:
DataTable.add(x,minY)
DataTable.add(x,maxY)
They'll be some spurious data on the graph, but the viewport will resize itself to your desired axis. Since these points are added at the end, they tend to be obscured somewhat, and are easy to ignore.
The following method worked for me:
plot.getAxis(XYPlot.AXIS_X).setRange(0.0, 4.0);
plot.getAxis(XYPlot.AXIS_Y).setRange(0.0, 20.0);
I am using vaadin and for some visual data analysis I've added the addon InvientCharts for vaadin (https://vaadin.com/directory#addon/invient-charts).
Is it possible to dynamically change the x- and y-axis Caption of the scattertchart (so after the chart has been created)?
I'm currently having a scatterchart and a button. When the button is clicked, all existing points (Series) shall be removed, the x- and y-axis caption shall change and the new points shall be added on the chart.
That's the code snippet with which I'm trying it currently:
public void changePoints(String xAxisTitle, String yAxisTitle, List<List<double[]>> xAndYCoordinates) {
// remove all points from the scatterchart - THIS IS WORKING
Object[] allSeries = chart.getAllSeries().toArray();
for(int j = 0; j < allSeries.length; j++){
Series serie = (Series) allSeries[j];
chart.removeSeries(serie);
}
// update the x- and y-axis - THIS IS NOT WORKING AND WHAT I'M TALKING ABOUT
chartConfig.getXAxes().clear();
chartConfig.getYAxes().clear();
NumberXAxis xAxis = new NumberXAxis();
xAxis.setTitle(new AxisTitle(xAxisTitle));
xAxis.setStartOnTick(true);
xAxis.setEndOnTick(true);
xAxis.setShowLastLabel(true);
LinkedHashSet<XAxis> xAxesSet = new LinkedHashSet<InvientChartsConfig.XAxis>();
xAxesSet.add(xAxis);
chartConfig.setXAxes(xAxesSet);
NumberYAxis yAxis = new NumberYAxis();
yAxis.setTitle(new AxisTitle(yAxisTitle));
LinkedHashSet<YAxis> yAxesSet = new LinkedHashSet<InvientChartsConfig.YAxis>();
yAxesSet.add(yAxis);
chartConfig.setYAxes(yAxesSet);
// add the new points - THIS IS WORKING AGAIN
for (int i = 0; i < versionDates.size(); i++) {
String versionDate = versionDates.get(i);
List<double[]> versionValues = xAndYCoordinates.get(i);
ScatterConfig versionScatterConfig = new ScatterConfig();
XYSeries series = new XYSeries("Version " + (i + 1) + " - "
+ versionDate, versionScatterConfig);
series.setSeriesPoints(getPoints(series, versionValues));
chart.addSeries(series);
}
}
As you can see, the removing and adding of points works perfectly fine, which I assume is because I'm working directly on the chart here, while I'm working on the chartConfig when I try to change the axes caption.
Could you please tell or show me how I can change the caption of the x- and y-Axis in an already existing chart (As described above)?
Thanks a lot
After a lot of research I've come to the conclusion that there seems to be currently no way of changing the x- and yAxis caption dnymically, which works.
I found out that if you refresh the page, e.g. by pressing F5, the axes caption gets changed. I've tried implementing a refresher, but somehow the behaviour still didn't change.
So it looks like a bug (or software failure) for me.
My workaround which is doing the same is just removing the whole chart and then adding a completely new one with the new Axis-caption. This works perfectly fast and fine, but is a dirty solution in my eyes, since you have to add more lines of codes than necessary, as well as the logic is now basically more complicated then it should be.
Can someone tell me how to change samples of series color in legend in jfreechart. What I have now is small line of series color eg: I would like to have square sample of those colors. Here is an example
Can someone help me?
Ok I found the solution. At least I think. Of course there is no simple way to do this. There is now, you know, setShape(square) method, that will do the trick, at least i haven't found one.
Basicly XY chart and time chart have "line style" legend by default in contrary to bar chart for example (if has square legend by default). So I had to remove current legend and create new one with square samples of color and this new legend add to my time chart.
LegendItemCollection legend = new LegendItemCollection();
for (int i = 0; i < seriecCount; ++i) {
chart.getXYPlot().getRenderer().setSeriesPaint(i, colorPalette.get(i));
LegendItem li = new LegendItem(data.getSeriesName(i), "-", null, null, Plot.DEFAULT_LEGEND_ITEM_BOX, colorPalette.get(i));
legend.add(li);
}
chart.getXYPlot().setFixedLegendItems(legend);
Thanks for attention. I hope it will help someone.
Generating your own legend, as you do above, is a perfectly acceptable way of doing things in JFreeChart. If you didn't want to do it, you can also define your own renderer with the lookupLegendShape() method overridden.
thePlot.setRenderer(new XYLineAndShapeRenderer()
{
public Shape lookupLegendShape(int series)
{
return new Rectangle(15, 15);
}
});
If you use a XYBarRenderer Class XYBarRenderer
(Subclasses: ClusteredXYBarRenderer, StackedXYBarRenderer)
You can use XYBarRenderer.setLegendBar(java.awt.Shape bar);
See: Javadoc
to get nice squares.
Example:
JFreeChart chart = ChartFactory.createXYBarChart(/*...*/);
XYPlot plot = (XYPlot) chart.getPlot();
ClusteredXYBarRenderer renderer = new ClusteredXYBarRenderer();
renderer.setLegendBar(new Rectangle(17, 17));
plot.setRenderer(renderer);