In mixed chart containing bars and a line, how to extend the line outside of the chart in both directions? - chart.js2

I have this chart, which has line and bars:
Is it possible to somehow extend the line outside of the chart in both directions? This line serves an important role, it is sort of a "limit" for bars, I just don't want for it to start at the center of the first bar, and to end at the center of the final bar.
I can extend it to the right by simply extending the dataset of the line, but is it possible to extend it also to the left somehow?

I figured out answer based on answer from this question: Is it able to align line chart at left margin in mixed chart?
I'm extending line type like this:
Chart.controllers.LineNoOffset = Chart.controllers.line.extend({
updateElement: function(point, index, reset) {
Chart.controllers.line.prototype.updateElement.call(this, point, index, reset);
const meta = this.getMeta();
const xScale = this.getScaleForId(meta.xAxisID);
point._model.x = xScale.getPixelForValue(undefined, index-0.5);
},
});
Now the LineNoOffset type of the line will start from the left border of the chart, which fulfills my need.

Related

Is there a way to get the ECharts series symbol to be passed in as the marker in the tooltip

I've got an ECharts chart that has multiple line series and a scatter series that represents events. For the line series, we left the symbol at the default, but for the event scatter series we set the symbol to 'diamond'. These symbols show up on the chart & in the series legend as expected. However, the tooltip always shows a 10 pixel dot for the marker. The color however is picked up from the series (and even from the visualMap config!). My initial assumption had been that the symbol would also be picked up from the series. In our case we wanted to use a function for tooltip.formatter and even in that function we couldn't figure out how to access and swap in the series symbol for the marker. We ended up working around it by just custom styling our own html to plug in for the marker that matched the diamond symbol pretty well.
So the open questions are:
Is there a way to have the tooltip marker pick up the symbol from the series?
If not, is this a bug? I'm happy to put in an issue on the project but I don't want to do that until I understand a bit more.
Here's some code to illustrate what we had to do to get the diamond in there in case it helps the discussion or if others want to leverage this workaround:
formatTooltip(args){
let time = DateTime.fromISO(args[0].data[0], { zone: this.user.timeZone })
let tooltip = `<div><b>${time.toFormat(TOOLTIP_FORMAT)}</b></div>`
args.forEach(({ marker, seriesName, value }) => {
if (seriesName === 'Events'){
let myMarker = `<span style="display:inline-block;margin-right:4px;width:10px;height:10px;background:${value[4]};transform:rotate(45deg);"></span>`
tooltip += `<div>${myMarker} ${value[3] ? value[3]: ''}</div>`
} else {
value = value || [0, 0]
tooltip += `<div>${marker} ${seriesName}: ${value[1]}</div>`
}
})
return tooltip
},

Trying to align text in center of rectangle while drawing freeText annotation but text goes in top left corner

I am trying to free text Annotation string align in center of rectangle but always set in top left corner
PdfContentByte pcb = stamper.getOverContent(page);
PdfAnnotation annotation = PdfAnnotation.createFreeText(stamper.getWriter(), rectangle, "Mayank Pandey", pcb);
annotation.put(PdfName.Q, new PdfNumber(PdfFormField.Element.ALIGN_MIDDLE));
Text showing left top corner in pdf:
You set
annotation.put(PdfName.Q, new PdfNumber(PdfFormField.Element.ALIGN_MIDDLE));
The constant Element.ALIGN_MIDDLE is defined as
/**
* A possible value for vertical alignment.
*/
public static final int ALIGN_MIDDLE = 5;
But the value of Q in free text annotations is specified as:
Q
integer
(Optional; PDF 1.4) A code specifying the form of quadding (justification) that shall be used in displaying the annotation’s text:
0 Left-justified
1 Centered
2 Right-justified
Default value: 0 (left-justified).
Thus, value 5 you used is not a valid Quadding value at all!
Furthermore, FreeText Quadding does not even support what you want to achieve, to align in center of rectangle, it only allows to select horizontal alignment, not vertical alignment.
For your objective, therefore, you'll have to use a custom appearance (which takes precedence if present).

Google Charts offsetting the horizontal axis marker labels

Does anyone know if its possible to offset the markers so they appear between the column of a google chart?
So that it appears like this design mockup...
Instead of the markers being directly inline with the columns like below which is the default behaviour of the google.visualization.ColumnChart api.
I have search through the documention, however cannot find any references to options that would allow for this kind of customisation. Does anyone know if perhaps there is a way of manipulating the layout after it has been rendered? Or if in fact there is an option to do this but I've just overlooked it?
Thanks
The chart is rendered in a <svg> structure containing <g>, <rect>, <text> (and other) elements. The structure differs a lot form chart to chart, and the internal ordering can change if basic chart elements are left out. The horizontal axis elements is rendered as something like
<text text-anchor="middle" x="468.46875" y="343.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">12</text>
To get an idea of where to look for those <text> elements in the <svg> structure you can copy the rendered code of the chart to a editor capable of styling code, or use a online code beautifier.
Then simply iterate through the <svg> by using DOM methods such as querySelector, querySelectorAll, getElementsByTagName etc.
See this google.visualization.ColumnChart :
By changing the x attribute of each <text> element that belongs to the horizontal axis we can get the labels to appear between the columns :
google.visualization.events.addListener(chart, 'ready', updateAxis);
function updateAxis() {
var x,
svg = document.getElementById('chart').querySelector('svg'),
g = svg.querySelectorAll('g'),
chartArea = g[3].querySelectorAll('g'),
hAxisTexts = chartArea[5].querySelectorAll('text');
//0-15 labels, the rest belongs to the yAxis
for (var i=0;i<16;i++) {
x = parseFloat(hAxisTexts[i].getAttribute('x'));
if (x>9) {
x = x-15;
} else {
x = x-18;
}
hAxisTexts[i].setAttribute('x', x);
}
}
demo -> http://jsfiddle.net/hrrL45oq/
This is only an example. You will perhaps need to target a different <g> element holding the <text>'s, and how you manipulate x or other attributes of <text> depends of the layout of the chart.

google charts annotations show right side of point

I am using google charts for plotting a graph
How can I show annotation of the point at right-hand-side of the point but it showing on the top of point
http://i.stack.imgur.com/UHhQH.png
I want it like as follow
http://i.stack.imgur.com/lUBcq.png
Please any one help me out
You can actually change the position of the annotations, by using css tranform.
You should first get a handle to the anntation text, if you want to change all the text, then you can use the text tag name in css
text {
transform: translate(10px, 30px);
}
I was able to adjust annotations to the right by doing 2 things:
1) Entered some white spaces (\u00A0 is white space) and a long dash (—) on the left side of the desired annotation.
2) Added stem length of -3.
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('string', 'Model');
dataTable.addColumn('number', 'T');
dataTable.addColumn({type:'string', role:'annotation'});
dataTable.addRows([
['ABC',30,'\u00A0\u00A0\u00A0\u00A0 — X'],
['DEF',20,'\u00A0\u00A0\u00A0\u00A0 — Y'],
['GHI',10,'\u00A0\u00A0\u00A0\u00A0 — Z'],
]);
var options = {
1: {annotations: {stem: {length: -3}}
};

Line chart/graph with an irregular threshold field

Looking to create a bar chart with an irregular, colored threshold field in the background, so that each data point has its own individual set of min/max thresholds, which ultimately would look something like this: http://dcalvitti.webs.com/plant/SAMPLE.png
Looked at D3 examples like this one: http://bl.ocks.org/mbostock/4062844
Can the latter example be manipulated to look more like the image I created?
Thanks in advance..
The graph shown in your sample image is actually much easier than the linked example; for that, you don't need to create a clipping path and you don't need to draw the line twice with two different colours.
For drawing the coloured background, use an area-path generator, created with d3.svg.area(). Set the y0 accessor function to be extract your minimum value for each point in your data array, and the y1 accessor function to extract the maximum value.
Then draw the line overtop as a normal line graph with a d3.svg.line() path generator.
Working example, adapted from the fiddles in the comments: http://jsfiddle.net/h45CD/12/
(Note: I commented out half the dataset, since the "year" values were repeated, not sure what that was supposed to represent.)
Key code:
// Define the value line path generator
var line = d3.svg.line()
.x( function(d) { return x(d.year); } )
.y( function(d) { return y(d.temp); } );
// Define the area path generator
var area = d3.svg.area()
.x( function(d) { return x(d.year); } )
.y0( function(d) { return y(d.min); } )
.y1( function(d) { return y(d.max); } );
/* ... */
// Add the background area showing the historic range
svg.append("path")
.datum(data)
.attr("class", "historicRange")
.attr("d", area);
// Add the value line
svg.append("path")
.datum(data)
.attr("class", "dataline")
.attr("d", line);
Edit based on comments
If you do want a line that changes colour depending on historic values, as opposed to a line drawn overtop of a background range, the most straight-forward solution is probably to create a <pattern> element consisting of the different coloured regions, and use this to stroke the value line.
You'll want to familiarize yourself with the different options for the pattern element. This MDN tutorial has a good intro, or you could dive into the full W3 specs.
For this situation, we want the pattern to be sized and positioned relative to the coordinate system used for drawing the line, regardless of the size or shape of the line itself. That means we will be setting both the patternUnits and the patternContentUnits to be userSpaceOnUse. The height and width of the pattern will be the height and width of the plotting area.
Within the pattern we will draw the area that represents the max-min range, but we also need to draw separate areas, with different colours, for values above the max and values below the min. We can use the same area generator for each, but need to change the y0/y1 accessor functions each time.
Key code:
// Add the pattern showing the historic range
var pattern = defs.append("pattern")
.datum(data) //add the data to the <pattern> element
//so it will be inherited by each <path> we append
.attr({
"patternUnits":"userSpaceOnUse",
"patternContentUnits":"userSpaceOnUse",
"width": width,
"height": height
})
.attr("id", "strokePattern");
pattern.append("path")
.attr("class", "historicRange between")
.attr("d", area);
pattern.append("path")
.attr("class", "historicRange above")
.attr("d", area.y1( 0 )
.y0( function(d){return y(d.max);} )
);
pattern.append("path")
.attr("class", "historicRange below")
.attr("d", area.y1( function(d){return y(d.min);} )
.y0( height )
);
// Add the value line
plot.append("path")
.datum(data)
.attr("class", "dataline")
.attr("d", line)
.style("stroke", "url(#strokePattern)");
Working example: http://jsfiddle.net/h45CD/14/
I'm including a web page link with charts authored by myself based on AMCharts and with the help of that web site's founder. Contains several examples of the above question and more..
http://dcalvitti.webs.com/SAMPLE/NEWWEBINDEX.html
The charts provided are still being worked on. For example, AMcharts does have a function that clips the color of a line above/below a certain value which I didn't know about, so there is still work to be done. I spent many weeks on the charts and thought I'd share. I'm sure someone will find something new here down the road...