Google barchart tooltip no tail - charts

Im using google barchart and I added tooltips with html in it. The problem is that the tooltip does not have the tail arrow thing. I saw that some charts has the arrow while others dont?
function drawFrequencyCharts(response) {
var data2 = new google.visualization.DataTable();
data2.addColumn('number', 'Value');
data2.addColumn('number', 'Value');
data2.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
.... some code
var view = new google.visualization.DataView(data2);
var chart2 = new google.visualization.ComboChart(document.getElementById('barChart'));
var options2 = {
height: 300,
width: 500,
series: {
0: {
type: 'bars'
},
1: {
type: 'line',
color: 'grey',
lineWidth: 0,
pointSize: 0,
visibleInLegend: false
}
},
colors: ['#3394D1'],
backgroundColor: {
fill: 'transparent'
},
legend: 'none',
vAxis: {
maxValue: 100,
minValue: 0,
ticks: [{
v: 0,
f: '0%'
}, {
v: 25,
f: '25%'
}, {
v: 50,
f: '50%'
}, {
v: 75,
f: '75%'
}, {
v: 100,
f: '100%'
}, ]
},
hAxis: {
format: '#',
viewWindowMode: 'explicit',
viewWindow: {
min: 0.1
},
title: 'Drops per day',
gridlines: {
color: 'transparent'
},
ticks: ticksValues
},
animation: {
duration: 750,
easing: 'linear',
startup: chartAnimate
}
};
chart2.draw(view, options2);

The problem with the "tail" is that you're using tooltip:{isHtml:true}. They are not shown with the tip, just an ordinary "box" floating above your chart.
If you revoke to "normal" tooltip, then you'll see the 'tail'.
JSFiddle where you can see the difference.

Related

(Chart.js 3.7.0) change position of x-axis ticks to alternate between each tick?

I have a chart which effectively renders a timeline, but sometimes the tick positions are too close together
Current graph (padding: 25)
I can change the padding to be negative which puts them above the x-axis:
Ticks above x-axis (padding: -60)
But I'd prefer them to alternate to above and below eg 1st tick below, 2nd tick above, 3rd tick below etc.
Can I access the individual ticks padding to do this? See below my current code:
ticks: {
source: 'data',
maxRotation: 90,
minRotation: 90,
font: {
size: 12,
},
autoskip: true,
padding: -60,
},
TIA for any help! :-)
You can define two identical datasets together with two x-axes. One of the x-axes with position: 'top', the other one with default position ('bottom').
A slightly different ticks.callback function on both x-axes makes sure that only every second tick is displayed.
ticks: {
source: 'data',
...
callback: (v, i) => i % 2 ? v : ''
},
Please take a look at the following runnable code and see how it works.
const data = [
{ x: "2022-03-22", y: 0 },
{ x: "2022-04-01", y: 0 },
{ x: "2022-04-02", y: 0 },
{ x: "2022-04-03", y: 0 },
{ x: "2022-04-08", y: 0 },
{ x: "2022-04-12", y: 0 },
{ x: "2022-04-15", y: 0 }
];
new Chart('chart', {
type: 'line',
data: {
datasets: [{
data: data,
backgroundColor: 'black',
pointRadius: 5,
pointHoverRadius: 5,
borderWidth: 2,
xAxisID: 'x'
},
{
data: data,
backgroundColor: 'black',
pointRadius: 5,
pointHoverRadius: 5,
borderWidth: 2,
xAxisID: 'x2'
}]
},
options: {
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: context => undefined
}
}
},
scales: {
y: {
ticks: {
display: false,
},
grid: {
display: false,
drawBorder: false
}
},
x: {
position: 'top',
type: 'time',
time: {
unit: 'day',
tooltipFormat: 'MMM DD'
},
ticks: {
source: 'data',
minRotation: 90,
callback: (v, i) => i % 2 ? v : ''
},
grid: {
display:false,
drawBorder: false
}
},
x2: {
type: 'time',
time: {
unit: 'day',
tooltipFormat: 'MMM DD'
},
ticks: {
source: 'data',
minRotation: 90,
callback: (v, i) => i % 2 ? '' : v
},
grid: {
display:false,
drawBorder: false
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#1.0.0"></script>
<canvas id="chart" height="50"></canvas>

Using ChartJS to create a multiple grouped bar chart - see picture below

I am testing out HighCharts and ChartJS to see which to use. For Highcharts, I was able to find a hack to create a bar chart that had double grouping on the x-axis.
This is what I want to look like:
I am new to both charting JS options and wonder if there is a way to do this in ChartJS.
I have the datasets something like this:
xAxis: {
categories: [{
name: "Total",
categories: ["2004", "2008", "2012"]
}, {
name: "Lower than 2.50",
categories: ["2004", "2008", "2012"]
}]
},
yAxis: {
min: 0,
title: {
text: 'Percent (%)'
}
},
series: [{
name: 'Male',
data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4]
}, {
name: 'Female',
data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6]
}]
Essentially I need a nest series on the x-axis and I am open to plugins or code from Github to do this.
You can make use of the Plugin Core API. It offers different hooks that may be used for executing custom code. In below code, I use the afterDraw hook to draw the category labels and the delimiter lines.
new Chart('myChart', {
type: 'bar',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
ctx.save();
let xAxis = chart.scales['x-axis-0'];
let xCenter = (xAxis.left + xAxis.right) / 2;
let yBottom = chart.scales['y-axis-0'].bottom;
ctx.textAlign = 'center';
ctx.font = '12px Arial';
ctx.fillText(chart.data.categories[0], (xAxis.left + xCenter) / 2, yBottom + 40);
ctx.fillText(chart.data.categories[1], (xCenter + xAxis.right) / 2, yBottom + 40);
ctx.strokeStyle = 'lightgray';
[xAxis.left, xCenter, xAxis.right].forEach(x => {
ctx.beginPath();
ctx.moveTo(x, yBottom);
ctx.lineTo(x, yBottom + 40);
ctx.stroke();
});
ctx.restore();
}
}],
data: {
labels: ['2004', '2008', '2012', '2016', '2004', '2008', '2012', '2016'],
categories: ['Total', 'Lower than 2.50'],
datasets: [{
label: 'Male',
data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4, 51.2, 51.8],
backgroundColor: 'rgba(124, 181, 236, 0.9)',
borderColor: 'rgb(124, 181, 236)',
borderWidth: 1
},
{
label: 'Female',
data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6, 53.7, 54.6],
backgroundColor: 'rgba(67, 67, 72, 0.9)',
borderColor: 'rgb(67, 67, 72)',
borderWidth: 1
}
]
},
options: {
legend: {
position: 'bottom',
labels: {
padding: 30,
usePointStyle: true
}
},
scales: {
yAxes: [{
ticks: {
min: 0,
max: 80,
stepSize: 20
},
scaleLabel: {
display: true,
labelString: 'Percent (%)'
}
}],
xAxes: [{
gridLines: {
drawOnChartArea: false
}
}]
}
}
});
canvas {
max-width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="200"></canvas>
You have to define a second x-axis and play around with the many ticks and gridLines options.
Please take a look at below runnable code and see how it could be done. This is obviously only a draft and needs to optimized and made more generic.
new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: ['2004', '2008', '2012', '2004', '2008', '2012'],
datasets: [{
label: 'Male',
data: [42.4, 43.0, 43.0, 50.3, 49.4, 48.4],
backgroundColor: 'rgba(124, 181, 236, 0.9)',
borderColor: 'rgb(124, 181, 236)',
borderWidth: 1
},
{
label: 'Female',
data: [57.6, 57.0, 57.0, 49.7, 50.6, 51.6],
backgroundColor: 'rgba(67, 67, 72, 0.9)',
borderColor: 'rgb(67, 67, 72)',
borderWidth: 1
}
]
},
options: {
legend: {
position: 'bottom',
labels: {
usePointStyle: true
}
},
scales: {
yAxes: [{
ticks: {
min: 0,
max: 80,
stepSize: 20
},
scaleLabel: {
display: true,
labelString: 'Percent (%)'
}
}],
xAxes: [{
gridLines: {
drawOnChartArea: false
}
},
{
offset: true,
ticks: {
autoSkip: false,
maxRotation: 0,
padding: -15,
callback: (v, i) => {
if (i == 1) {
return 'Total';
} else if (i == 4) {
return 'Lower than 2.50';
} else {
return '';
}
}
},
gridLines: {
drawOnChartArea: false,
offsetGridLines: true,
tickMarkLength: 20,
color: ['white', 'white', 'white', 'lightgray', 'white', 'white', 'lightgray']
}
}
]
}
}
});
canvas {
max-width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="200"></canvas>

Echarts:how to set markLine lable above the line and at the end of the line?

In echarts-3.6.2, when I set position:'end' for markLine, the lable will display at the end of line
markLine: {
data: [{
symbol:"none",
name: 'GOAL',
yAxis: 3.12 ,
label:{
normal:{
show:true,
position:'end'
}
},
lineStyle: {
normal: {
color: '#5C57FF',
width: 2
}
},
}]
},
However, I want to dislay it above the line at the end of the line? How to make it?
Change position value to insideEndTop(see in docs):
markLine: {
data: [{
symbol: "none",
name: 'GOAL',
yAxis: 3.12,
label: {
normal: {
show: true,
position: 'insideEndTop'
}
},
lineStyle: {
normal: {
color: '#5C57FF',
width: 2
}
},
}]
},
hello,do you have any ideas for not using position: 'insideEndTop', I could not upgrade the echarts plugin
I can't help without a crutch/workaround because it's very old version. You need to update the Echarts immediately, it's only right way. Or you can try to simulate markLine with the graphic component, something like below but it's highway to hell.
var myChart = echarts.init(document.getElementById('main'));
var option = {
color: ['rgba(92, 87, 255, 0.3)'],
grid: {
left: 50,
bottom: 50,
},
graphic: [{
type: 'group',
id: 'markLine',
bounding: 'raw',
children: [{
id: 'lineShape',
$action: 'replace',
type: 'line',
invisible: true,
shape: {
x1: 50,
y1: 300,
x2: 120,
y2: 300,
},
style: {
stroke: '#5C57FF',
lineWidth: 2,
},
zlevel: 10,
}, {
type: 'polygon',
$action: 'replace',
id: 'arrowShape',
invisible: true,
scale: [0.5, 0.3],
position: [90, 292.5],
shape: {
points: [
[16, 5],
[16, 47],
[38, 26]
]
},
style: {
fill: '#5C57FF',
}
}, {
type: 'text',
$action: 'replace',
id: 'labelShape',
invisible: true,
style: {
text: 'GOAL: 3.12',
x: -100,
y: 290,
fill: '#5C57FF',
font: 'bolder 12px sans-serif',
},
zlevel: 10,
}],
}],
xAxis: {
data: ["1", "2", "3", "4", "5", "6"]
},
yAxis: {
type: 'value',
max: 50
},
series: [{
name: 'Series',
type: 'bar',
data: [5, 20, 36, 10, 10, 20],
}]
};
myChart.setOption(option);
function renderMarkLine({ instance, yAxisValue, text, speed }){
var currentStep = 0;
var arrowShape = (val) => {
return {
stopCoord: 710, // 525
opts: {
invisible: false,
id: 'arrowShape',
position: [5 + val, yAxisValue - 7.5] // yAxisValue + 7.5
}
}
};
var lineShape = (val) => {
return {
stopCoord: 680, //540
opts: {
id: 'lineShape',
invisible: false,
shape: {
x1: 50,
y1: yAxisValue, // +0
x2: 50 + val,
y2: yAxisValue
}
}
}
};
var labelShape = (val) => {
return {
stopCoord: 660, // 460
opts: {
id: 'labelShape',
invisible: false,
style: {
x: -10 + val,
y: yAxisValue - 10, // 10
fill: '#5C57FF',
font: 'bolder 12px sans-serif'
}
}
}
};
var interval = setInterval(function(){
var graphicData = [];
[arrowShape, lineShape, labelShape].forEach(el => {
if (el(null).stopCoord > currentStep){
graphicData.push(el(currentStep).opts);
}
});
if (graphicData.length === 0) clearInterval(interval);
instance.setOption({ graphic: graphicData });
currentStep += 10;
}, speed);
};
renderMarkLine({ instance: myChart, yAxisValue: 500, speed: 0 });
<script src="https://cdn.jsdelivr.net/npm/echarts#3.6.2/dist/echarts.min.js"></script>
<div id="main" style="width:800px;height:600px;"></div>

How to set min start date for Highcharts plot?

I have data from 10/19 to 11/01 and I am plotting it using a scattered Highcharts plot (v4.1.10, cannot upgrade). For some reason my x-axis is showing 10/18, but I want it to start with 10/19. I tried using pointStart, but this did not work. Any suggestions on how to get the correct starting date to show in my x-axis?
Highcharts.chart('container', {
yAxis: {
gridLineWidth: 0.5,
gridLineColor: '#D6D6D6',
tickInterval: 5,
dashStyle: 'LongDash',
lineColor: '#D6D6D6'
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
day: '%m/%d',
week: '%d/%b',
month: '%b/%y',
year: '%Y'
},
title: {
enabled: true,
text: 'date'
},
gridLineWidth: 0,
lineColor: '#D6D6D6',
lineWidth: 0.5,
startOnTick: true
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: this.toolTip
}
},
chart: {
marginTop: 5,
marginRight: 0,
reflow: false,
backgroundColor: 'rgba(255, 255, 255, 0.1)',
style: {
fontFamily: 'Open Sans'
},
type: 'scatter',
spacingBottom: 0,
spacingTop: 0,
spacingLeft: 0,
spacingRight: 0
},
tooltip: {
formatter: function () {
var s = '<b>' + Highcharts.dateFormat('%m/%d %H:%M:%S', this.x)
+ ' - ' + Highcharts.numberFormat(this.y, 2);
return s;
},
},
series: values
});
jsfiddle code here
You can set the x axis min value:
xAxis: {
min:1539950400000
Example: http://jsfiddle.net/jlbriggs/dwnx6o8e/9/
Depending on the data and other options, you may need to look at other properties, like startOnTick, tickInterval, etc.

Messed up LineChart with highcharts

I'm using HighCharts to display charts on my site.
What I'd like to achieve is just a line chart with (zoomable) Date-Time X-Axis and numbers in Y-Axis.
But the result is messed up:
I load data by an ajax call, create an array and use chart.series[0].setData(chartData); to set the chart's data. Below is a sample for chartData:
[[1343071800000, 17], [1343158200000, 171], [1343244600000, 291], [1343075400000, 18],
[1343161800000, 74], [1343248200000, 293], [1343165400000, 183], [1343251800000, 296]]
Also, I use DotNetHighCharts since I'm using ASP.NET MVC 3, but the generated javascript to create the chart is as follows:
chart = new Highcharts.Chart({
chart: { renderTo:'chart_container' },
legend: { align: 'left', borderWidth: 0, floating: true, layout: 'horizontal', verticalAlign: 'top', y: 20 },
plotOptions: { series: { cursor: 'pointer', marker: { lineWidth: 1 }, point: { events: { click: function() { alert(Highcharts.dateFormat('%A, %b %e, %Y', this.x) +': '+ this.y +' visits'); } } } } },
subtitle: { text: 'Source: Google Analytics' },
title: { text: 'Daily visits at www.highcharts.com' },
tooltip: { crosshairs: true, shared: true },
xAxis: { gridLineWidth: 1, labels: { align: 'left', x: 3, y: -3 }, tickInterval: 604800000, tickWidth: 0, type: 'datetime' },
yAxis: [{ labels: { align: 'left', x: 3, y: 16, formatter: function() { return Highcharts.numberFormat(this.value, 0); } }, showFirstLabel: false, title: { text: '' } }, { gridLineWidth: 0, labels: { align: 'right', x: -3, y: 16, formatter: function() { return Highcharts.numberFormat(this.value, 0); } }, linkedTo: 0, opposite: true, showFirstLabel: false, title: { text: '' } }],
series: [{ name: 'All visits' }]
Your dataset is not in chronological order. So the charting system is joining all the points as best it can.
For time-based series it is always best to sort your time from earliest to latest.