Plotly.js: update text of each node using restyle - javascript

Is it possible to update the text inside the treemap plot using restyle function?
I know it's possible via 'react' function, but this function will redraw the entire diagram (I don't want this to happen).
This what I have so far: https://codepen.io/elv1s42/pen/yLydprX
var labels = ["P1", "P2", "P3", "P4"];
var parents = ["", "P1", "P1", "P2"];
var data = [{
type: "treemap",
labels: labels,
parents: parents,
marker: { colors: ['green', 'blue', 'red', 'yellow']},
text: ['text1', 'text2', 'text3<br>text3', 'text4'],
textinfo: "label text"
}];
var layout = {};
Plotly.newPlot('myDiv', data, layout)
function changeText(){
var upd = {
marker: {colors: ['white', 'orange', 'green', 'red']},
//text: ['t1', 't2', 't3', 't4'] // how to update the text?
};
Plotly.restyle('myDiv', upd);
}
<head>
<!-- Load plotly.js into the DOM -->
<script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
</head>
<body>
<button onclick='changeText()'>Change my plot!</button>
<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>
</body>

I don't like answering my own questions, but the issue was resolved by https://github.com/etpinard from GitHub here: https://github.com/plotly/plotly.js/issues/4535
So the working solution is to use nested arrays for the text field:
function changeText(){
var upd = {
marker: {colors: ['white', 'orange', 'green', 'red']},
text: [['t1', 't2', 't3', 't4']] // how to update the text?
};
Plotly.restyle('myDiv', upd);
}
The CodePen example from the question is fixed now.

Related

Changing legend text in chart js causing issues

I'm trying to shorten my chart legends, so I'm using the beforeRender plugin to change the text of the legend. However, once the chart is drawn, it seems to keep the original label size (see below snippet, legends are offset to the left instead of in the centre and if you click on orange, it toggles one of the earlier items).
The same happens if I try in beforeDraw and if I use beforeInit or beforeLayout, the legends don't seem to have been created yet.
Is there any way to get the chart to redraw the legends with the new text? Or change the legend text so that it is rendered properly?
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'pie',
data: {
labels: ['red - some other text that appears after', 'blue - some other text that appears after', 'green - some other text that appears after', 'orange - some other text that appears after'],
datasets: [{
data: [4, 2, 10, 3],
backgroundColor: ['red', 'blue', 'green', 'orange'],
}],
},
options: {
responsive: true,
},
plugins: [{
beforeRender: chart => {
chart.legend.legendItems.forEach(label => {
const labelParts = label.text.split(' - ');
const newLabel = label;
newLabel.text = labelParts[0];
return newLabel;
});
},
}],
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
<div style="width: 100%">
<canvas id="canvas"></canvas>
</div>
A better approach would be to use a custom generateLabels function like so:
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'pie',
data: {
labels: ['red - some other text that appears after', 'blue - some other text that appears after', 'green - some other text that appears after', 'orange - some other text that appears after'],
datasets: [{
data: [4, 2, 10, 3],
backgroundColor: ['red', 'blue', 'green', 'orange'],
}],
},
options: {
responsive: true,
legend: {
labels: {
generateLabels: function(chart) {
const data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
const meta = chart.getDatasetMeta(0);
const style = meta.controller.getStyle(i);
return {
text: label.split(' - ')[0],
fillStyle: style.backgroundColor,
strokeStyle: style.borderColor,
lineWidth: style.borderWidth,
hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
}
}
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
<div style="width: 100%">
<canvas id="canvas"></canvas>
</div>

ChartJS: Highlight dataset in a stacked bar chart when hovering over the legend?

I've got a horizontal stacked bar chart rendered in Chart.js, and the legend corresponds to the different classes. Here's a bit of it (working on a dummy dataset, disregard the nonsense names):
The labels on the left are users, the labels in the legend (which correspond to the classes in the bar chart, i.e. the different datasets) are mailing lists. The chart, basically, shows how many users are members of specific mailing lists; the length of the bar is how many mailing lists a given user is a member of.
What I'd like to do is set it up so hovering over an entry in the legend will highlight (ideally with a border or something) the portions of the bar chart corresponding to that dataset. So if I hovered over the first dataset entry, the blue block at the left end of all those bars (except "anionic") would get a highlight.
Using the onHover and onLeave events for the legend, I'm successfully console.log'ing the currently-hovered dataset index. But I can't figure out how to make the bar elements belonging to that dataset highlight.
With the new upcomming release of version 3 you can do this with the setActive elements.
Documentation: https://www.chartjs.org/docs/master/developers/api/#setactiveelementsactiveelements
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1,
hoverBackgroundColor: 'green',
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1,
hoverBackgroundColor: 'red',
}
]
},
options: {
scales: {}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
chart.setActiveElements([{
datasetIndex: 0,
index: 1,
}, {
datasetIndex: 1,
index: 1,
}]);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.0-beta.10/chart.js" integrity="sha512-7igYTuENB1pHNsZ/SyzMYrcJAmRCk084yVOsxNNCQAdX1wSYvCeBOgSOMC6wUdKMO76kCJNOpW4jY3UW5CoBnA==" crossorigin="anonymous"></script>
</body>
Using ChartJS 3 setActiveElements API, you can highlight an entire dataset on legend hover using the following code in options.plugins.legend
onHover: function (event, legendItem) {
const datasetIndex = legendItem.datasetIndex;
let elementList = [];
for (let i = 0; i < this.chart.getDatasetMeta(datasetIndex).data.length; i++) {
elementList.push({
'datasetIndex': datasetIndex,
'index': i,
});
}
this.chart.setActiveElements(elementList);
this.chart.update();
}

Pushing arrays using jexcel plugin to customize a subtitle editor

Please be kind enough to let me know how I can push arrays using the jexcel plugin.
https://bossanova.uk/jexcel/v3/
The push functionality must work in the exact same way as for arrays with 6 different colors as shown below.
Subtitles = orange,
Captions = yellow,
Chapters = blue,
Description = lime,
Interaction purple,
Metadata = pink
var data = [
["Subtitles"],
["Captions"],
["Chapters"],
["Description"],
["Interaction"],
["Metadata"],
];
jexcel(document.getElementById('spreadsheet'), {
data:data,
columns: [
{
type: 'hidden',
},
{
title: 'Subtitles',
},
{
title: 'Captions',
},
{
title: 'Chapters',
},
{
title: 'Description',
},
{
title: 'Interaction',
},
{
title: 'Metadata',
},
],
});
I tried using the following code but it does not work in the proper way.
titlesArray = ["Subtitles", "Captions", "Chapters", "Description", "Interaction", "Metadata"];
var colors = ["orange", "yellow", "blue", "lime", "purple", "pink"];
for(var index = 0; index < subtitles.length; index++) {
var newArray = titlesArray.push("Subtitles", "Captions", "Chapters", "Description",
"Interaction", "Metadata");
}
$('p').css('color', function(index) {
return colors[index % colors.length];
});
The screenshot includes the way the colors should display for the respective titles but should happen for all 6 subtitles without changing the respective color.
I need the title French colored in blue and the title English colored in Orange which includes a font with a specific size as the two headings on top of the last two boxes shown on the very first row shown in the screenshot.
maybe i don't understand as you want. but i try give you an help
For your table, i suggest use JSON (object with property) to load data in jExcel.
var data = [
{"Subtitles":"YourValue", "Captions":"YourValue", "Chapters":"YourValue", "Description":"YourValue", "Interaction":"YourValue", "Metadata":"YourValue"},
/* ... */
]
For style, in jexcel options, you have an option updateTable (https://bossanova.uk/jexcel/v4/examples/table-scripting)
And on this function you can define dynamicaly style like
var colors = ["orange", "yellow", "blue", "lime", "purple", "pink"];
if(color[col]) {
cell.style.backgroundColor = color[col];
}

Chart not rendering with pug/jade and nodejs

I'm trying (about a week!!) to render a chart that works totally fine with hardcoded labels, but with my labels (data) from MySQL it shows nothing but a blank page.
However, if I console.log my labels, it shows me all the data sent from my DB which I want to put as labels to my chart.
In my index.js:
router.get('/api', function (req, res) {
axios.get('http://localhost:3000/projetos/quantos/ci')
.then(dados =>{
const d = dados.data;
var labelsx = [];
for(var i = 0; i < d.length; i++){
labelsx.push(d[i].Nome);
}
console.log(labelsx);
var datax = [];
for(var j = 0; j < d.length; j++){
datax.push(d[j].QuantosHa)
}
console.log(datax);
res.render('chart',
{title: "chart",
datai: JSON.stringify(datax),
labeli: labelsx
})
})
.catch(erro => {e: erro});
});
My chart.pug:
extends layout
block content
script(src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js")
div
each l in labeli
ul=l
div
.chart-container
canvas#chartPic
script.
var ctx = document.getElementById("chartPic").getContext('2d');
ctx.canvas.parentNode.style.width = '50%';
var idata = #{datai};
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: [],
datasets: [{
data: idata,
backgroundColor: ['red', 'green', 'blue', 'pink', 'black'],
borderColor: ['green', 'blue', 'red', 'black', 'pink'],
borderWidth: 1
}]
},
options: {
title: {
display: true,
text: "top 5 centros com mais projetos"
},
legend: {
position: 'bottom'
}
}
});
If i put, for example ["one", "two", "three", "four", "five"] in my chart's labels field it render with no problem and also that "each l in labeli" works just fine, but everytime I try to pass it to my chart, page goes blank like this:
If i put it like its showing the pug code I get the chart:
Can someone help me? Thanks in advance for any suggestion you may have!
Inside index.js, you should not convert datax to a string but simply pass the original array. Remove JSON.stringify from the code block below.
res.render('chart',
{ title: "chart",
datai: JSON.stringify(datax),
labeli: labelsx
})
It should looks as follows.
res.render('chart',
{ title: "chart",
datai: datax,
labeli: labelsx
})
UPDATE
In chart.pug you forgot to define the labels. Instead of an empty array, you should change the code as follows.
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: #{labeli}, // <- make this change
It might be to late to answer this question but I was also facing the same issue and couldn't find any answer. The following steps did the trick.
Remove JSON stringify before sending the response
res.render('chart',
{
title: "chart",
datai: datax,
labeli: labelsx
}
)
And Data is returned in a single comma separated string. So I use the String.split function to create an array.
{
//...
datasets: [{
data: ('#{datai}').split(','),
backgroundColor: ['red', 'green', 'blue', 'pink', 'black'],
borderColor: ['green', 'blue', 'red', 'black', 'pink'],
borderWidth: 1
}],
//...
}

Changing labels with logo images

I'm trying to build a graph with chart.js and i would like to replace the labels with logtype small images.
Is it possible ? Can't find the way to do it.
Thanks.
This is my chart options:
var horizontalBarChartData3 = {
labels: ["mark1", "mark2", "mark3", "mark4","mark5"],
datasets: [
{
label: 'USA',
backgroundColor: "rgba(196,196,196,0.5)",
data: [0.07,0.02,0.26,0.68,0.21]
},
{
hidden: false,
label: 'EUROPA',
backgroundColor: "rgba(125,125,125,0.5)",
data: [0.09,0.02,0.31,0.74,0.23]
},
{
label: 'CHINA',
backgroundColor: "rgba(165,157,4,0.5)",
data: [0.15,0.02,0.38,0.99,0.27]
}]
};
Adding an image to the labels is a tricky adjustment, and will require fiddling with chart.js code, as it isn't natively supported. My best suggestion is to avoid attempts to add your images to the labels themselves.
Best solution for using icons would be one of:
Use images of your own, but place them around the chart in proper positions, and if needed, refer to em in labels.
Use an icon font to insert icons as characters of text. Here's an example using Font Awesome, using your data (based off of this fiddle):
var randomScalingFactor = function () {
return Math.round(Math.random() * 100);
};
var barChartData = {
pointLabelFontFamily: "'FontAwesome'",
labels: ["\uf000", "\uf001", "\uf002", "\uf003", "\uf004"],
datasets: [
{
label: 'USA',
backgroundColor: "rgba(196,196,196,0.5)",
data: [0.07,0.02,0.26,0.68,0.21]
},
{
hidden: false,
label: 'EUROPA',
backgroundColor: "rgba(125,125,125,0.5)",
data: [0.09,0.02,0.31,0.74,0.23]
},
{
label: 'CHINA',
backgroundColor: "rgba(165,157,4,0.5)",
data: [0.15,0.02,0.38,0.99,0.27]
}]
};
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive: true,
scaleFontFamily: "'FontAwesome'"
});
<script src="http://chartjs.org/assets/Chart.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css">
<div style="width: 75%">
<span style="font-family: FontAwesome"></span>
<canvas id="canvas" height="450" width="600"></canvas>
</div>

Categories

Resources