Logarithmic scale with jFreeChart BoxAndWhiskerChart - jfreechart

I've got a box and whisker chart being populated like so:
JFreeChart chart = ChartFactory.createBoxAndWhiskerChart(
"Average Fitness",
"Generation",
"Fitness",
aveDataSet,
true);
ChartFrame frame = new ChartFrame("Average Fitness", chart);
frame.pack();
frame.setVisible(true);
But the scale of the data makes the chart hard to read. At the left of the x-axis, the values are in the neighborhood of 250 000 000, but by about the halfway point the values are below 10 (but still converging toward 0). This long-tail convergence is impossible to see with the linear y-axis, but I can't figure if I'm able to replace it with a log scale.

Related

Create Fatter Candlesticks in JFreeChart

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);

Openlayers 3 Circle radius in meters

How to get Circle radius in meters
May be this is existing question, but i am not getting proper result. I am trying to create Polygon in postgis with same radius & center getting from openlayers circle.
To get radius in meters I followed this.
Running example link.
var radiusInMeters = circleRadius * ol.proj.METERS_PER_UNIT['m'];
After getting center, radius (in meters) i am trying to generate Polygon(WKT) with postgis (server job) & drawing that feature in map like this.
select st_astext(st_buffer('POINT(79.25887485937808 17.036647682474722 0)'::geography, 365.70644956827164));
But both are not covering same area. Can any body please let me know where i am doing wrong.
Basically my input/output to/from Circle will be in meters only.
ol.geom.Circle might not represent a circle
OpenLayers Circle geometries are defined on the projected plane. This means that they are always circular on the map, but the area covered might not represent an actual circle on earth. The actual shape and size of the area covered by the circle will depend on the projection used.
This could be visualized by Tissot's indicatrix, which shows how circular areas on the globe are transformed when projected onto a plane. Using the projection EPSG:3857, this would look like:
The image is from OpenLayer 3's Tissot example and displays areas that all have a radius of 800 000 meters. If these circles were drawn as ol.geom.Circle with a radius of 800000 (using EPSG:3857), they would all be the same size on the map but the ones closer to the poles would represent a much smaller area of the globe.
This is true for most things with OpenLayers geometries. The radius, length or area of a geometry are all reported in the projected plane.
So if you have an ol.geom.Circle, getting the actual surface radius would depend on the projection and features location. For some projections (such as EPSG:4326), there would not be an accurate answer since the geometry might not even represent a circular area.
However, assuming you are using EPSG:3857 and not drawing extremely big circles or very close to the poles, the Circle will be a good representation of a circular area.
ol.proj.METERS_PER_UNIT
ol.proj.METERS_PER_UNIT is just a conversion table between meters and some other units. ol.proj.METERS_PER_UNIT['m'] will always return 1, since the unit 'm' is meters. EPSG:3857 uses meters as units, but as noted they are distorted towards the poles.
Solution (use after reading and understanding the above)
To get the actual on-the-ground radius of an ol.geom.Circle, you must find the distance between the center of the circle and a point on it's edge. This could be done using ol.Sphere:
var center = geometry.getCenter()
var radius = geometry.getRadius()
var edgeCoordinate = [center[0] + radius, center[1]];
var wgs84Sphere = new ol.Sphere(6378137);
var groundRadius = wgs84Sphere.haversineDistance(
ol.proj.transform(center, 'EPSG:3857', 'EPSG:4326'),
ol.proj.transform(edgeCoordinate, 'EPSG:3857', 'EPSG:4326')
);
More options
If you wish to add a geometry representing a circular area on the globe, you should consider using the method used in the Tissot example above. That is, defining a regular polygon with enough points to appear smooth. That would make it transferable between projections, and appears to be what you are doing server side. OpenLayers 3 enables this by ol.geom.Polygon.circular:
var circularPolygon = ol.geom.Polygon.circular(wgs84Sphere, center, radius, 64);
There is also ol.geom.Polygon.fromCircle, which takes an ol.geom.Circle and transforms it into a Polygon representing the same area.
My answer is a complement of the great answer by Alvin.
Imagine you want to draw a circle of a given radius (in meters) around a point feature. In my particular case, a 200m circle around a moving vehicle.
If this circle has a small diameter (< some kilometers), you can ignore earth roudness. Then, you can use the marker "Circle" in the style function of your point feature.
Here is my style function :
private pointStyle(feature: Feature, resolution: number): Array<Style> {
const viewProjection = map.getView().getProjection();
const coordsInViewProjection = (<Point>(feature.getGeometry())).getCoordinates();
const longLat = toLonLat(coordsInViewProjection, viewProjection);
const latitude_rad = longLat[1] * Math.PI / 180.;
const circle = new Style({
image: new CircleStyle({
stroke: new Stroke({color: '#7c8692'});,
radius: this._circleRadius_m / (resolution / viewProjection.getMetersPerUnit() * Math.cos(latitude_rad)),
}),
});
return [circle];
}
The trick is to scale the radius by the latitude cosine. This will "locally" disable the distortion effect we can observe in the Tissot Example.

XYSeries autorange loss of precision?

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.

R - Contour map

I have plotted a contour map but i need to make some improvements. This is the structure of the data that are used:
str(lon_sst)
# num [1:360(1d)] -179.5 -178.5 -177.5 -176.5 -175.5 ...
str(lat_sst)
# num [1:180(1d)] -89.5 -88.5 -87.5 -86.5 -85.5 -84.5 -83.5 -82.5 -81.5 -80.5 ...
dim(cor_Houlgrave_SF_SST_JJA_try)
# [1] 360 180
require(maps)
maps::map(database="world", fill=TRUE, col="light blue")
maps::map.axes()
contour(x=lon_sst, y=lat_sst, z=cor_Houlgrave_SF_SST_JJA_try[c(181:360, 1:180),],
zlim=c(-1,1), add=TRUE)
par(ask=TRUE)
filled.contour(x = lon_sst, y=lat_sst,
z=cor_Houlgrave_SF_SST_JJA_try[c(181:360, 1:180),],
zlim=c(-1,1), color.palette=heat.colors)
Because most of the correlations are close to 0, it is very hard to see the big ones.
Can i make it easier to see, or can i change the resolution so i can zoom it in? At the moment the contours are too tightly spaced so I can't see what the contour levels were.
Where can i see the increment, i set my range as (-1,1), i don't know how to set the interval manually.
Can someone tell me how to plot a specific region of the map, like longitude from 100 to 160 and latitude from -50 to -80? I have tried to replace lon_sst and lat_sst, but it has a dimension error. Thanks.
To answer 1 and 3 which appear to be the same request, try:
maps::map(database="world", fill=TRUE, col="light blue",
ylim=c(-80, -50), xlim=c(100,160) )
To address 2: You have a much smaller range than [-1,1]. The labels on those contour lines are numbers like .06, -.02 and .02. The contour function will accept either an 'nlevels' or a 'levels' argument. Once you have a blown up section you can use that to adjust the z-resolution of contours.
contourplot in the lattice package can also produce these types of contour plots, and makes it easy to both contour lines and fill colours. This may or may not suit your needs, but by filling contour intervals, you can do away with the text labels, which can get a little crowded if you want to have high resolution contours.
I don't have your sea surface temperature data, so the following figure uses dummy data, but you should get something similar. See ?contourplot and ?panel.levelplot for possible arguments.
For your desired small scale plot, overlaying the world map plot is probably inappropriate, especially considering that the area of interest is in the ocean.
library(lattice)
contourplot(cor_Houlgrave_SF_SST_JJA_try, region=TRUE, at=seq(-1, 1, 0.25),
labels=FALSE, row.values=lon_sst, column.values=lat_sst,
xlim=c(100, 160), ylim=c(-80, -50), xlab='longitude', ylab='latitude')
Here, the at argument controls the position at values at which contour lines will be calculated and plotted (and hence the number of breaks in the colour ramp). In my example, contour lines are provided at -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75 and 1 (with -1 being the background). Changing to at=seq(-1, 1, 0.5), for example, would produce contour lines at -0.5, 0, 0.5, and 1.

jFreeChart: DateAxis to behave like a CategoryAxis. Only discrete datevalues to be printed

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);

Resources