I am using JFreeChart to display a value for each day of a month.
Now I want to have my x-axis display the weeks in a month instead of the days.
At the moment the values for my graph are double on the y-axis and int on the x axis.
Timestamp ts = a.getTimestamp();
Double val = a.getVal();
series1.add(ts.getDate(), val);
I am using
plot.getDomainAxis().setRange(0, 31);
to set the range for the days to one month and
xax.setTickUnit(new NumberTickUnit(7));
for the x-axis to display the ticks at the right position. Instead of displaying the days (0, 7, 14, 21, 28) i want them to be weeks (0, 1, 2, 3, 4).
Is that even possible, and how would I be able to do that?
You should use a DateAxis for your time axis, like ChartFactory.createTimeSeriesChart() does. Then you can use setDateFormatOverride(), like they show here, and the SimpleDateFormat for "week in month."
JFreeChart chart = ChartFactory.createTimeSeriesChart(…);
DateAxis axis = (DateAxis) chart.getXYPlot().getDomainAxis();
axis.setDateFormatOverride(new SimpleDateFormat("W"));
Related
I am working on a Graph visualizer toolkit which scans a text file and shows it as a line Graph on a jPanel. The format of valid a text file is:
Title: <graph title>
YLabel: <y-axis label>
XLabel: <x-axis label>
XStart: <x-axis start value>
XInterval: <x-axis interval value>
<data>
At this point, I've already validated and stored the values needed for the graph. So basically what I need to do now is generalize the XStart, XInterval and data value to a coordinate system to fit the jPanel, GraphBoard, as the data can and will vary from one file to another.
I did some thinking and thought about using some if-else statements to filter the data and drawing separate graphs for each, I wanna say, type of the data. But immediately discarded it because the process would be repetitive. And right now I'm stuck trying to come up with a brilliant algorithm that will, well cover all kinds of datasets. I hope I explained myself well enough. here is the code i have so far:
public class Coordinator {
public final static double UNIT = 20;
protected double xStartCoords, xIntervalCoords, xStart, xInterval;
protected Double[] yValuesCoords, yValues;
protected int index = 0;
protected Double maxYValue, range;
public Coordinator(double xStart, double xInterval, Double[] yValues) {
this.xStart = xStart;
this.xInterval = xInterval;
this.yValues = yValues;
xyz();
}
public void xyz() {
//code needed
}
}
And here are some valid text files:
1.
Title: Effect of Age on Ability
YLabel: Ability
XLabel: Age
XStart: 0
XInterval: 15
0, 3, 4.2, 7, 5.1, 10, 3.2
2.
Title: Difference between Fly Weights
YLabel: Weight
XLabel: Age
XStart: 0.25
XInterval: 0.025
100.02, 100.03, 99.98, 99.99, 100.01, 100.02, 100.05, 100.06, 100.07, 100.01, 100.00, 99.98, 99.97, 99.96
3.
Title: Inverse expansion
YLabel: Size
XLabel: Time
XStart: 0
XInterval: 100000
0, 20000, 30000, 35000, 40000, 43000, 50000, 60000, 62000, 90000
So you see where I'm having trouble. A few suggestions to tackle this would be great. Thanks.
You want to scale the data to the required chart dimensions.
In other words calculate what is the representation in pixels for a data unit.
For x axis you could use :
xPixlesPerUnit = chartWidth / xRange
where xRange is (xInterval * numberOfYs).
Applied to text file #1 , assuming you want the chart to be 1000 pixels wide:
xRange = 15 * 7 = 105 , so 105 units should be 1000 pixels wide
xPixlesPerUnit = 1000/105 = 9.52
This means that last x (=105) will be plotted at 105*95.2 = 1000.
You handle Y scale similarly, where
yRange = yMax - yMin
This is the basic idea. There are many implementation issues to handle like rounding, margins, negative axis (or having more than one quadrant).
I was able to make a Gantt Chart in JavaFX using this answer- Gantt chart from scratch.
Also i was able to add a DateAxis by using this-http://myjavafx.blogspot.com.by/2013/09/javafx-charts-display-date-values-on.html
But right now it is unusable, because current Gantt chart does not handle "length" as a date. So it draws the beginning of the the chart perfectly accurately, but the end of the chart can be anywhere, and if you resize the window with the chart, the end will be even more random.
I am adding new chart with
.add(new XYChart.Data(job.getTime(), machine, new ExtraData( timeLength, "status-red"))
where "timeLength" i set as number of milliseconds. But basicly that does not work, and it can only receive long.Also i cannot use JfreeChart, because i cannot add it FXML which i use.
So how can i get accurate both beginning and the end of each chart?
Thank you.
Add the following function to DateAxis class to calculate the scale factor from milliseconds to visual units.
/**
* #return The scale factor from milliseconds to visual units
*/
public double getScale(){
final double length = getSide().isHorizontal() ? getWidth() : getHeight();
// Get the difference between the max and min date.
double diff = currentUpperBound.get() - currentLowerBound.get();
// Get the actual range of the visible area.
// The minimal date should start at the zero position, that's why we subtract it.
double range = length - getZeroPosition();
return length/diff;
}
Test results
Date startDate=new Date();
long duration = 1000*60*1;//1 hour in milliseconds
series1.getData().add(new XYChart.Data(startDate, machine, new ExtraData(duration, "status-green")));
startDate = new Date(startDate.getTime()+duration);
duration = 1000*60*1;//2 hours in milliseconds
series1.getData().add(new XYChart.Data(startDate, machine, new ExtraData(duration, "status-red")));
screenshot 1
Is there a way to show only the (say) bottom and right borders of a rectangle? Is the rectangle width/height based on the centerlines of the border strokes? Am I conflating css border with the rectangle's strokes or are they in fact the same thing?
My bigger problem in context:
A partial screenshot:
In the lower half of of the picture there are two independent "week-lines"/"calendars". Each little square represents a day. There are 5 per column, representing Mo Tu We Th Fr of the same week. There are roughly four columns (representing weeks) per month.
I would like to introduce a small gap between months. If the month changes over a weekend, the corresponding gap would just be a thin vertical line. Otherwise it would have a "step" in it.
Each day's square is a Rectangle on its own little StackPane in its own cell of a GridPane. (I can change the contents of the cells in the GridPane if I really have to, as long as I can still color each cell's interior freely.) The Rectangle sizes are set on construction. Here is a code fragment showing what I tried (This runs for each cell):
StringBuilder stylebuilder = new StringBuilder("-fx-border-width: 1; -fx-border-color: white; -fx-border-style: hidden;");
Month month = date.getMonth();
if(month != date.plusDays(1).getMonth()){
stylebuilder.append("-fx-border-bottom-style: solid;");
}
if(month != date.plusWeeks(1).getMonth()){
stylebuilder.append("-fx-border-right-style: solid;");
}
if(month != date.minusDays(1).getMonth()){
stylebuilder.append("-fx-border-top-style: solid;");
}
if(month != date.minusWeeks(1).getMonth()){
stylebuilder.append("-fx-border-left-style: solid;");
}
rectangle.setStyle(stylebuilder.toString());
Any advice would be appreciated.
I was indeed conflating strokes with borders. Any Shape (and therefore any Rectangle) has strokes, not borders.
The solution was to do away with the rectangles, background-color the panes, and inset the background to get the boundaries:
pane.setMinSize(cellSize, cellSize);
pane.setPrefSize(cellSize, cellSize);
pane.setMaxSize(cellSize, cellSize);
Month month = date.getMonth();
insets = new Insets(
month != date.minusDays(1).getMonth() ? monthSepWidth/2 : 0,
month != date.plusWeeks(1).getMonth() ? monthSepWidth/2 : 0,
month != date.plusDays(1).getMonth() ? monthSepWidth/2 : 0,
month != date.minusWeeks(1).getMonth() ? monthSepWidth/2 : 0
);
pane.setBackground(new Background(new BackgroundFill(color,CornerRadii.EMPTY,insets)));
I want to create a Linegraph with JFreechart. My Data is like :
Number1,Number2,Timestamp
So I want two Lines Where the Y-Axis is Number1 and Number2 and the X-Axis it the Timestamp.
I save the Chart as a png Image and the X-Axis looks just to long I think it is because of the timestamp beeing long apart.
I Searched google and Stackoverflow but answers like this dont work for me. How can i Fix this?
Here is my code:
TimeSeries ts = new TimeSeries("Systole");
ts.add(new Minute(new Date(1356999660000L)), 141);
ts.add(new Minute(new Date(1356999840000L)), 129);
ts.add(new Minute(new Date(1433074800000L)), 146);
ts.add(new Minute(new Date(1433075700000L)), 136);
TimeSeries diast = new TimeSeries("Diastole");
diast.add(new Minute(new Date(1356999660000L)), 95);
diast.add(new Minute(new Date(1356999840000L)), 86);
diast.add(new Minute(new Date(1433074800000L)), 98);
diast.add(new Minute(new Date(1433075700000L)), 91);
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(systole);
dataset.addSeries(diastole);
XYDataset data = dataset;
final TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(ts);
dataset.addSeries(diast);
XYDataset data = dataset;
//String title, String timeAxisLabel, String valueAxisLabel, XYDataset dataset
JFreeChart chart = ChartFactory.createTimeSeriesChart("Blutdruck", "", "", data);
SaveImage(chart.createBufferedImage(500,500),"Test1.png");
The "vertical lines" effect happens because you are plotting a series that fluctuates on very different scales (minutes vs. years). Obviously, the variations at the scale of a minute are completely invisible when plotting them over a period of two years. It is like trying to draw the streets of a city on the map of a country.
There is no out-of-the-box solution for that problem, but you could find inspiration from the typical share price plots (from Google or Yahoo), where they let the user choose the scale they want to use.
Variation over five days:
Variation over three months:
Note that the variation over three months is smoother than the variation over five days. The reason is that they do not try to plot the value at every minute. Instead, they "subsample" their data.
In other words, they take the average over one day and plot only the values for each day.
I want to display some dates in the X axis of a chart, and here it is said that i have to use a TimeSeriesCollections object
It seems that i have to add a TimeSeries to the TimeSeriesCollections, and that the TimeSeries has to be constructed using a RegularTimePeriod...
I am a bit confused...
Can you please explain me what i have to do?
If possible can you provide some example code?
Thanks
TimeSeriesCollections are made up of TimeSeries objects
Use this method to add series to the dataset: addSeries(TimeSeries series)
When creating TimeSeries objects. Fill them with the time and values. Here is a rough example:
TimeSeries ts= new TimeSeries("Name of Series");
ts.addOrUpdate(new Year(2008), 42);
ts.addOrUpdate(new Year(2009), 51);
ts.addOrUpdate(new Year(2010), 97);
ts.addOrUpdate(new Year(2011), 45);
For getting the Axis to display the dates nicely, you will have to do something like this:
XYPlot plot = chart.getXYPlot();
DateAxis axis = new DateAxis();
plot.setDomainAxis(axis);
axis.setDateFormatOverride(new SimpleDateFormat("yyyy"));