JFreeChart - Datasets versus Series? - jfreechart

I am creating an XYPlot with initially null dataset, and then add multiple (e.g. 2) XYSeriesCollection instances to it. Like
val chart = ChartFactory.createXYLineChart(...)
val plot = chart.getXYPlot
plot.setDataset(0, dataset0)
plot.setDataset(1, dataset1)
Now I want them to have them in different colors and strokes:
import BasicStroke._
val renderer = plot.getRenderer
renderer.setSeriesPaint(0, Color.black)
renderer.setSeriesPaint(1, Color.red)
renderer.setSeriesStroke(0, new BasicStroke(2.0f))
renderer.setSeriesStroke(1,
new BasicStroke(2.0f, CAP_ROUND, JOIN_ROUND, 1.0f, Array(6f, 6f), 0f))
)
But both appear in black and non-dashed. So I must be making a mistake in terms of understanding the correspondence between datasets and series?
I also tried with plot.getRendererForDataset(dataset), but again, both datasets are controlled by the settings for series 0, while the renderer settings for series 1 seem to be irrelevant.

I don't know what the purpose of plot.setDataset(idx, _) is, but the XYSeriesCollection itself needs to have the different series included.
val series: Seq[XYSeries] = ...
val dataset = new XYSeriesCollection
series.foreach(dataset.addSeries _)
val chart = ChartFactory.createXYLineChart("title", "x", "y", dataset,
PlotOrientation.VERTICAL, true, false, false)
val plot = chart.getXYPlot
val renderer = plot.getRenderer
renderer.setSeriesPaint (0, paint0 )
renderer.setSeriesStroke(0, stroke0)
renderer.setSeriesPaint (1, paint1 )
renderer.setSeriesStroke(1, stroke1)
...

Related

how to apply normal map texture to custom geometry in scenekit, ios?

I'd created a custom SCNGeometry using following code:
let data = NSData(bytes: position, length: MemoryLayout<float3>.size * self.objectMesh.pointCount)
let vertexSource = SCNGeometrySource(data: data as Data,
semantic: .vertex,
vectorCount: self.objectMesh.pointCount,
usesFloatComponents: true,
componentsPerVector: 3,
bytesPerComponent: MemoryLayout<Float32>.size,
dataOffset: 0,
dataStride: MemoryLayout<float3>.size)
let data2 = NSData(bytes: uvs, length: MemoryLayout<float2>.size * self.objectMesh.pointCount)
let tSource = SCNGeometrySource(data: data2 as Data,
semantic: .texcoord,
vectorCount: self.objectMesh.pointCount,
usesFloatComponents: true,
componentsPerVector: 2,
bytesPerComponent: MemoryLayout<Float32>.size,
dataOffset: 0,
dataStride: MemoryLayout<float2>.stride)
let indexData = NSData(bytes: faces, length: MemoryLayout<Int32>.size * self.objectMesh.faceCount)
let element = SCNGeometryElement(
data: indexData as Data,
primitiveType: .triangles,
primitiveCount: self.objectMesh.faceCount/3,
bytesPerIndex: MemoryLayout<Int32>.size)
let Geometry = SCNGeometry(sources: [vertexSource, tSource], elements: [element])
Geometry.firstMaterial?.diffuse.contents = self.MainTexture
Geometry.firstMaterial?.normal.contents = self.NormalTexture
now the problem is: the texture shows up but the normal texture map is not applied to the geometry. I'm not going to use per vertex normals. this texture and normaltexture are works when applied to for example SCNPlane geometry. but I don't now how to use a normal map texture with my custom geometry.
The normal property on SCNMaterial expects a normal map in tangent space and then the effective normals are based on a combination of the normal map and the vertex normals of your custom geometry.
Model i/o includes MDLMesh which provide an addNormals method that can be used to create the normals programmatically (create an MDLMesh based on the SCNGeometry, use addNormals, and create a SCNGeometry based on the MDLMesh and use that new SCNGeometry instead). But ideally you include the normals with the custom geometry.

Data and Series label not showing on WinForm Chart control

I am having a problem getting the default WinForms Chart control to work. I have a single chart with a single area. In this area, I want to display three (3) series whose labels are on a single legend.
Each of the value arrays shown in the code below contains six (6) values.
When I run the application the chart is only showing the background with the title and the name of the FIRST series I defined, the others seem to be ignored. Also, no grid and no data points or lines are displayed. The chart is basically blank.
this.chart.SuspendLayout();
this.chart.ChartAreas.Clear();
this.chart.Series.Clear();
ChartType chartType = ChartType.Column;
// prepare the area
const string AREA_NAME = "ChartAreaBP";
ChartArea bpChartArea = new ChartArea(AREA_NAME);
bpChartArea.AxisX.LabelStyle.Format = "dd/MMM\nyyyy";
bpChartArea.AxisX.MajorGrid.LineColor = System.Drawing.Color.LightGray;
bpChartArea.AxisY.MajorGrid.LineColor = System.Drawing.Color.LightGray;
bpChartArea.BackColor = System.Drawing.Color.LimeGreen;
bpChartArea.BackGradientStyle = GradientStyle.DiagonalRight;
bpChartArea.Position.Auto = true;
bpChartArea.InnerPlotPosition.Auto = true;
this.chart.ChartAreas.Add(bpChartArea);
// prepare the values. X is Date/time all other 3 are BYTE/INT
var xvals = from x in items select x.TimeStamp;
var yvalsSys = from y in items select y.Systolic;
var yvalsDia = from y in items select y.Diastolic;
var yvalsRhy = from y in items select y.Rhythm;
// The first series, other 2 omitted from HERE for simplicity
const string SYS_SERIES = "Systolic";
Series sysBPSeries = new Series(SYS_SERIES, 4);
sysBPSeries.ChartType = chartType;
sysBPSeries.ChartArea = AREA_NAME;
sysBPSeries.XValueType = ChartValueType.Auto;
sysBPSeries.YValueType = ChartValueType.Date;
sysBPSeries.XAxisType = AxisType.Primary;
sysBPSeries.YAxisType = AxisType.Primary;
sysBPSeries.Enabled = true;
this.chart.Series.Add(sysBPSeries);
this.chart.Series[SYS_SERIES].Points.DataBindXY(xvals, yvalsSys);
// here the other two series are defined.
But when I run the application only the legend of the FIRST series is shown even though the other two are defined in the code (I omitted them from this listing) just the same way as the first series.
And as I stated above, no grid nor values are shown. However, the chart shown in design mode does show all three labels on the first and only legend and all three lines.

Swift - Create circle and add to array

I've been looking for a little while on how to create a circle in Swift, but it seems quite complicated. I want to create a circle at run time, with a specified x and y, and width and height. I then want to add this circle to an array where I can create more circles and add to it.
How do I do this?
Edit: This is what I've tried so far:
var center : CGPoint = touchLocation
var myContext : CGContextRef = UIGraphicsGetCurrentContext()
let color : [CGFloat] = [0, 0, 1, 0.5]
CGContextSetStrokeColor (myContext, color);
CGContextStrokeEllipseInRect (myContext, CGRectMake(touchLocation.x, touchLocation.y, 20, 20));
touchLocation is the location of the users finger. This crashes on execution on this line:
var myContext : CGContextRef = UIGraphicsGetCurrentContext()
The error says "Unexpectedly found nil while unwrapping an Optional value
Also, this doesn't allow me to add the circle to an array, because I don't know what variable type it is.
There are many ways to draw a circle, here is a snippet that I have been hacking with:
func circleWithCenter(c:CGPoint, radius r:CGFloat,
strokeColor sc: UIColor = UIColor.blackColor(),
fillColor fc: UIColor = UIColor.clearColor()) -> CAShapeLayer {
var circle = CAShapeLayer()
circle.frame = CGRect(center:c, size:CGSize(width:2*r, height:2*r))
circle.path = UIBezierPath(ovalInRect:circle.bounds).CGPath
circle.fillColor = fc.CGColor
circle.strokeColor = sc.CGColor
circle.fillColor = fc == UIColor.clearColor() ? nil : fc.CGColor
return circle
}
Note that I extended CGRect (using Swift specific features) to add a initializer that takes a center, but that is not material to your question.
Your code is not "creating" a circle as an object, it is attempting to draw one in the graphics context. What you need to do is to create a bezier path object, draw into that and save the path in your array. Something like:
var circleArray = [CGMutablePathRef]()
// ...
let path: CGMutablePathRef = CGPathCreateMutable()
CGPathAddArc(path, nil, touchLocation.x, touchLocation.y, radius, 0, M_PI * 2, true)
circleArray += [path]
You then need to stroke the path(s) in your draw routine.

Change point labels on plot created by plotTangentSpace in "geomorph" package

Here is a classical example found on the help page for plotTangentSpace in package geomorph. I just add two lines: the construction of the vector Myname and the following line that name one dimension of the array Y.gpa$coords according to Myname.
library (geomorph)
data(plethodon)
Y.gpa<-gpagen(plethodon$land) #GPA-alignment
ref<-mshape(Y.gpa$coords)
Myname = 41:80
dimnames(Y.gpa$coords)=list(NULL, NULL, Myname)
plotTangentSpace(Y.gpa$coords, label=T)
As you can see, on the plot created by plotTangentSpace the points are labeled 1:40 rather than 41:80 as I aimed to do by renaming Y.gpa$coords. I'd like to label the points according to Myname. For this example my name is just a vector of numbers but I'd like it to works for character type also. How can I achieve this?
If you have a look at the code for plotTangentSpace (just type it in the R console), you first find the 'argument list':
function (A, axis1 = 1, axis2 = 2, warpgrids = TRUE, label = FALSE)
As you see you can turn labels 'on' or 'off' (label = TRUE or FALSE), but there is no argument for setting the actual value of the labels. Further down you find the code for the default, hard-coded labels (seq(1, n)) in two places:
if (label == T) {
text(pcdata[, axis1], pcdata[, axis2], seq(1, n),
adj = c(-0.7, -0.7))
...where pcdata, axis1, and n are defined in the beginning of the function.
Thus, if you want to set the value of the labels, it seems that you need to rewrite the function slightly. One possibility is to add a labels argument to the arglist:
function (A, axis1 = 1, axis2 = 2, warpgrids = TRUE, label = FALSE, labels = NULL)
...and change the arguments in both text calls:
text(pcdata[, axis1], pcdata[, axis2], labels,
adj = c(-0.7, -0.7))
You also need to access the tps function in the geomorph namespace. This can be achived by adding geomorph::: before both instances of tps:
geomorph:::tps(ref, shape.min, 20)
geomorph:::tps(ref, shape.max, 20)
Then assign the updated function to a new function name:
plotTangentSpace2 <- function (A, axis1 = 1, axis2 = 2, warpgrids = TRUE, label = FALSE, labels = NULL){
lots-of-stuff
text(pcdata[, axis1], pcdata[, axis2], labels,
adj = c(-0.7, -0.7)) # in both places
more-stuff
geomorph:::tps(ref, shape.min, 20)
geomorph:::tps(ref, shape.max, 20)
}
Plot with the updated function, using 'Myname' as labels:
plotTangentSpace2(Y.gpa$coords, label = TRUE, labels = Myname)

Amcharts SerialChart multiple line graphs different category value member paths (Silverlight)

EDIT I rewrote my question to make it more understandable after the conversation below with Tony (thanks!).
GOAL Render multiple line graphs (let's say 2) in the same chart. The charts have different x/y value pairs. For one x-value, I do not know both y-values.
I am using Silverlight. The classes available for this are SerialChart and LineGraph. The data source for both graphs is the same and is set at the SerialChart level. The name of the property for the x-axis is also defined there for both graphs (CategoryValueMemberPath).
As suggested by the amCharts documentation, we need to create objects that have a property for the category axis (x-axis) and then one property per graph. Let's call them "Graph1" and "Graph2". So the data source looks something like this:
List<MyClass> data = new List<MyClass>()
{
new MyClass() { Category = 0.1, Graph1 = 0.14, Graph2 = ??? }
,new MyClass() { Category = 0.15, Graph1 = ???, Graph2 = 0.05 }
,new MyClass() { Category = 0.2, Graph1 = 0.35, Graph2 = ??? }
,new MyClass() { Category = 0.18, Graph1 = ???, Graph2 = 0.12 }
... and so on ...
}
PROBLEM What am I supposed to do about the "???" values? I do not have the actual value for that graph for that category value.
If I do not set a value, the default value of 0.0 is assumed and it draws a spike to the x-axis. If I set the previously known Graph1/Graph2 value, then it creates a horizontal connection where there is not supposed to be one. I am basically altering the graph which leads to a wrong result.
So how do I solve this? I am getting the feeling that amCharts do not support this scenario.
You need to add two 'value' axes, one in the X direction and one in the Y direction (imagine, like a bubble chart).
// AXES
// X
var xAxis = new AmCharts.ValueAxis();
xAxis.position = "bottom";
xAxis.gridAlpha = 0.1;
xAxis.autoGridCount = true;
chart.addValueAxis(xAxis);
// Y
var yAxis = new AmCharts.ValueAxis();
yAxis.position = "left";
yAxis.gridAlpha = 0.1;
yAxis.autoGridCount = true;
chart.addValueAxis(yAxis);
Merge all your data points into one array with a common X axis field name ('x' in my example) and for points on line 1, add a property of 'line1' with its value, and for points on line 2, add a property of 'line2'.
For example, your data would look like this:
var chartData = [
{x:0.1,line1:0.25},
{x:0.246,line1:0.342},
{x:0.12,line2:0.16},
{x:0.3,line2:0.485}
];
Then add a 'graph' for each line to your chart specifying where to get the value from in the object array.
// GRAPHS
var graph = new AmCharts.AmGraph();
graph.xField = "x";
graph.yField = "line1";
graph.lineAlpha = 1;
graph.lineColor = '#FF9E01';
chart.addGraph(graph);
var graph2 = new AmCharts.AmGraph();
graph2.xField = "x";
graph2.yField = "line2";
graph.lineAlpha = 1;
graph2.lineColor = '#9EFF01';
chart.addGraph(graph2);
I've put all this into a Fiddle for you - http://jsfiddle.net/64EWx/

Resources