Is there any way to add multiple axis on lineWithFocusChart .
I want to add my y2axis on right side of the graph.
There is a default option in the NVD3 library to draw multiple axis chart. Just look into the example of multichart at the documentation website of the library. And a sample html file is provided on the github repo of nvd3
You can use Barchart, Areachart and line chart for multiple axis.
Just draw the graph with
var chart = nv.models.multiChart()
And change the yAxis variable to draw the graph on left yaxis or right yaxis like this.
testdata[0].type = "area";
testdata[0].yAxis = 1;
testdata[1].type = "area";
testdata[1].yAxis = 1;
testdata[2].type = "line";
testdata[2].yAxis = 1;
testdata[3].type = "line";
testdata[3].yAxis = 2;
testdata[4].type = "bar";
testdata[4].yAxis = 2;
testdata[5].type = "bar";
testdata[5].yAxis = 2;
testdata[6].type = "bar";
testdata[6].yAxis = 2;
Related
CartesianGrid allows me to set the verticalPoints and horizontalPoints to be shown.
Unfortunately, these values are in pixel values on the chart, not in the coordiantes of the x and y domains.
I must be missing something. I have an x-axis and a y-axis. How can I map a value in those domains into positions on the chart?
So, given some constants defining the chart:
const chartWidth = 600; // width set on our chart object
const xAxisLeftMargin = 10; // margins set on our chart object
const xAxisRightMargin = 20;
const xPadding = 0; // padding set on both sides of xAxis
const yAxisWidth = 120; // total widths of all yAxes
we can use d3 to create an xScale, like this:
const leftX = 0 + yAxisWidth + xAxisLeftMargin + xPadding;
const rightX = chartWidth - xPadding - xAxisRightMargin;
// note that rightX assumes there are no axes on the right hand side
const xScale = d3.scaleLinear().domain(xDomain).range([leftX, rightX]);
Then assuming we have an array of verticalPoints:
const verticalPoints: number[] = [];
we just add values in the xDomain like this:
verticalPoints.push(xScale(value))
and we can render our vertical lines on the x-axis with the CartesianGrid like this:
<CartesianGrid stroke="#d5d5d5" verticalPoints={verticalPoints} />
I am adding images using chart.renderer.image. I would like the images to line up with the beginning of each plotBand. I have the plotBand from position in axis units. However when I call toValue the images do not line up.
https://jsfiddle.net/uxeL76a9/23/
for (var i = 0; i < plotBands.length; ++i) {
var artist = plotBands[i];
var xPos = chart.xAxis[0].toValue(artist['from'], true);
...
Your chart is inverted, so axes are swapped, and you have small mess with toValue(), see fixed code:
var xPos = chart.xAxis[0].toValue(artist['from'], true);
Should be:
var xPos = chart.yAxis[0].toPixels(artist.from);
Working demo: https://jsfiddle.net/uxeL76a9/40/
I have chart for OS X app that can be resized with the window. I expected when the width was reduced enough the legend would be truncated or clipped. However, it is spilling outside of the plot area as shown below. Ideally, I would like the legend to truncate or at least clip the contents. how can this be done?
My legend setup is as follows
- (void)configureLegend
{
// 1 - Get graph instance
CPTGraph *graph = self.graphHostingView.hostedGraph;
// 2 - Create legend
CPTLegend *theLegend;
if (!theLegend) {
theLegend = [CPTLegend legendWithGraph:graph];
}
//Configure Text
CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
textStyle.color = [CPTColor colorWithComponentRed:0.612f green:0.612f blue:0.612f alpha:1.00f];
textStyle.fontName = #"HelveticaNeue";
textStyle.fontSize = 12.0f;
theLegend.textStyle = textStyle;
// 3 - Configure legend
theLegend.numberOfColumns = 1;
theLegend.fill = nil;
theLegend.borderLineStyle = nil;
theLegend.swatchSize = CGSizeMake(10.0, 10.0);
theLegend.swatchCornerRadius = 5.0f;
// 4 - Add legend to graph
graph.legend = theLegend;
graph.legendAnchor = CPTRectAnchorLeft;
CGFloat viewWidth = self.graphHostingView.bounds.size.width;
CGFloat legendPadding = (viewWidth * 0.3) + self.pieChart.pieRadius + (viewWidth * 0.05);
graph.legendDisplacement = CGPointMake(legendPadding, 0.0);
}
Make sure the graph is masking its sublayers. Use masksToBounds to clip to the outside of the border line or masksToBorder to clip to the inside edge of the border.
I am using the code snippet from this stackoverflow question to label my flot data points. So far this has served me well, but now I have to label the overall values of stacked bars. There are two data series and so far I've managed to calculate the sums, but I can't seem to work out a proper positioning for my labels. I'd like to place them on top of the stacks, but pointOffset only gives me the offsets based on non-stacked bars.
This is the code I am currently using, it places the labels where the second series' data points would be, if the bars weren't stacked, which puts them somewhere in the top bars.
$.each(p.getData()[1].data, function(i, el){
var series0 = p.getData()[0].data;
sum = el[1] + series0[i][2]
var o = p.pointOffset({x: el[0], y: el[1]});
$('<div class="data-point-label">' + sum + '</div>').css( {
position: 'absolute',
left: o.left - 5,
top: o.top ,
display: 'none'
}).appendTo(p.getPlaceholder()).fadeIn('slow');
});
Edit #1: So far I've tried using c2p/p2c, calculating the top value using the single data points' top values and finding more documentation on the stack plugin. I am afraid none of this has helped me much.
Edit #2: I've also tried the code given in this stackoverflow answer but it doesn't work for me. I suspect the author is using some label plugin ...
The solution to put the labels in the top of the bars in stack usinjg canvas is that you have to calculate the xPoint in base of the sum of the values in the complete stack.
Here is a example of code
var sumaArr = [];
for (var u = 0; u < p.getData().length; u++) {
$.each(p.getData()[u].data, function (i, el) {
sumaArr[i] > 0 ? sumaArr[i] = sumaArr[i] + el[1] : sumaArr[i] = el[1];
});
}
var ctx = p.getCanvas().getContext("2d");
var data = p.getData()[p.getData().length - 1].data;
var xaxis = p.getXAxes()[0];
var yaxis = p.getYAxes()[0];
var offset = p.getPlotOffset();
ctx.font = "12px 'Segoe UI'";
ctx.fillStyle = "gray";
for (var i = 0; i < data.length; i++) {
var text = sumaArr[i];
var metrics = ctx.measureText(text);
var xPos = (xaxis.p2c(data[i][0]) + offset.left) - metrics.width / 2;
var yPos = yaxis.p2c(sumaArr[i]) + offset.top - 5;
ctx.fillText(text, xPos, yPos);
}
The var yPos use the sume of the values that make the complete stack.
I have just started using jqPlot for a line chart with multiple series. It seems great.
I have added the Cursor plugin with the intention of showing a vertical line on the nearest data point on the x axis. In other words, it snaps to the nearest point. The Cursor plugin, however always shows the vertical cursor right where the mouse is.
It seems like I just want to "override" or replace moveLine to change the current functionality.
What's the most appropriate way of doing so?
It seems a little much to copy/past all of the cursor plugin just to modify a very small subset.
Thanks!
I know I'm a kind of archaeologist by edited this post but I think the following can be useful for someone (I hope).
I've made a piece of code which allow to draw a vertical line following the cursor and displaying a tooltip on the nearest point (according to the cursor). You can find a demo of it on this JSFiddle.
I also post the corresponding code below (only the part which calculate nearest point and display tooltip):
//Show nearest point's tooltip
$("#chart1").bind('jqplotMouseMove', function(ev, gridpos, datapos, neighbor, data){
var c_x = datapos.xaxis;
var index_x = -1;
var pos_index = 0;
var low = 0;
var high = data.data[0].length-1;
while(high - low > 1){
var mid = Math.round((low+high)/2);
var current = data.data[0][mid][0];
if(current <= c_x)
low = mid;
else
high = mid;
}
if(data.data[0][low][0] == c_x){
high = low;
index_x = high;
}else{
var c_low = data.data[0][low][0];
var c_high = data.data[0][high][0];
if(Math.abs(c_low - c_x) < Math.abs(c_high - c_x)){
index_x = low;
}else{
index_x = high;
}
}
//Display marker and tooltip
if(data.series[0].data[index_x]){
var x = data.series[0].gridData[index_x][0];
var y = data.series[0].gridData[index_x][1];
var r = 5;
var highlightCanvas = $(".jqplot-highlight-canvas")[0];
var context = highlightCanvas.getContext('2d');
context.clearRect(0,0,highlightCanvas.width,highlightCanvas.height);
context.strokeStyle = 'rgba(47,164,255,1)';
context.fillStyle = 'rgba(47,164,255,1)';
context.beginPath();
context.arc(x,y,r,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
//Display tooltip on nearest point
var highlightTooltip = $(".jqplot-highlighter-tooltip");
var val_x = data.data[0][index_x][0];
var val_y = data.data[0][index_x][1];
highlightTooltip.html("X : "+val_x+"<br/>Y : "+val_y);
highlightTooltip.css({'left': x+'px', 'top': (y-10)+'px', 'display': 'block'});
}
});
Feel please to use it and to modify it as you need it.
Try a bar graph series on top of everything else that has alpha set to 0.