dygraphs icon indicating copy to clipboard operation
dygraphs copied to clipboard

"connectSeparatedPoints:true" produces "undefined" in legend for missing values.

Open noamparn opened this issue 7 years ago • 13 comments

The example "Connect-Separated" displays this problem very clearly: http://dygraphs.com/tests/connect-separated.html

If you click the toggles at the bottom to set them to "true," you get "undefined" for any point that is missing data in the graph.

I am seeing this on my own pages using the 2.0.0 version (same as here). However, my own pages work fine if I go back to the 1.1.1 code.

noamparn avatar Mar 27 '17 00:03 noamparn

Repro: https://jsfiddle.net/eM2Mg/9541/

danvk avatar Mar 29 '17 01:03 danvk

The JSFiddle (above) shows the problem. Line 3 of the data has a missing (null) "Z" data point. Moving the mouse over the graph at that point shows "undefined" in the legend for the "Z" value. Previously, it just wouldn't display anything for a null value.

noamparn avatar Apr 20 '17 13:04 noamparn

I reported this bug almost 2 months ago, but there has been no acknowledgement of the bug yet.

noamparn avatar May 25 '17 00:05 noamparn

The bug has been acknowledged. There's generally no SLA for volunteer-driven open source projects.

danvk avatar May 26 '17 02:05 danvk

I've stumbled into this problem too. I've realized that the problem is present only when the datasource is a js obj, not in case the graph is populated via CSV.

Any news about a workaround?

dandigregorio avatar Feb 14 '18 10:02 dandigregorio

I've stumbled into this problem too. I've realized that the problem is present only when the datasource is a js obj, not in case the graph is populated via CSV.

This is happening to me but with a CSV source as well. For example:

2019-02-21 21:34:29,,99.62,
2019-02-21 22:24:28,87.49,,

If you have a valueFormatter it's not even being called, so apparently you cannot manually fix this.

ALobpreis avatar Feb 28 '19 14:02 ALobpreis

I had the same problem. I could work around it by filling up my input data to not contain any null values. I did this by filling up the missing values with the last "known" value, i.e. creating a stair function but interpolation will work as well. However, I am not plotting the original data anymore but this was fine for the project.

mkreim avatar May 03 '19 11:05 mkreim

I just also had the exact same problem and couldn't workaround it. A fix would be very welcome. Why not just calling valueFormatter in any case, maybe with a separate option 'callValueFormatterForUndefinedValues' defaulting to false for backwards compatibility?

djromberg avatar Aug 26 '19 13:08 djromberg

*** English version below ***

Sehr geehrte Damen und Herren,

ich bin bis einschließlich zum 11. September 2019 nur eingeschränkt per E-Mail und Telefon erreichbar. Ihre E-Mails werden nicht weiter geleitet. In dringenden Fällen kontaktieren Sie bitte meinen Kollegen Daniel Rech ([email protected] , +491626477725).

Vielen Dank für Ihr Verständnis.

Mit freundlichen Grüßen

Michael Kreim

*** English ***

Dear Sir or Madam,

Thank you for your message.

I am currently out of the office and will be back on 12th September 2019. Your e-mail will not be forwarded. In urgent cases please contact my colleague Daniel Rech ([email protected] , +491626477725). Thank you very much.

Kind regards,

Michael Kreim

mkreim avatar Aug 26 '19 13:08 mkreim

This is fairly easy to solve using legendFormatter. Check for missing values in your callback and handle them how you see fit.

CameronSinclair84 avatar Oct 25 '19 12:10 CameronSinclair84

Based on what CameronSinclair84 said, I did some test and indeed that function is what renders the whole legend line, instead of just each series' value. So if you overwrite it, you will have to include several lines of code to achieve the exact same default output. I wouldn't call that 'fairly easy'. ;)

I took a look at the code in http://dygraphs.com/2.1.0/dygraph.js and found where the problem lies. In the Legend.defaultFormatter function, near the end, you have to replace + series.yHTML + with + (series.yHTML || "") + (or whatever you want to be displayed instead of "undefined"). So you either fix the source JS file, or copy the whole function, fix it and add it in options.legendFormatter.

I also tried to find a fix where yHTML is set instead (function Legend.generateLegendHTML), which theoretically is a call to valueFormatter, but that function is indeed not called in this scenario, so I'm not sure what's going on there.

PS: You have a very short (and probably buggy) version for legendFormatter here, where this feature was requested.

ALobpreis avatar Oct 25 '19 17:10 ALobpreis

What I mean is you can pass in a callback function as an option in the options block to handle this.

Read here under legendFormatter: http://dygraphs.com/options.html#Legend

My callback looks like this:

legendFormatter(data: any) { if (data.x == null) { return data.series.map(element => { return '<span style="font-weight:bold; color:' + element.color + ';">' + '<div class="dygraph-legend-line" style="border-bottom-color:' + element.color + ';"></div>' + ' ' + element.labelHTML + '</span><br>'; }).join(' '); } else { return data.xHTML + '<br>' + data.series.map(element => { if (element.yHTML) { return '<span style="font-weight:bold; color:' + element.color + ';">' + '<div class="dygraph-legend-line" style="border-bottom-color:' + element.color + ';"></div>' + ' ' + element.labelHTML + ': ' + element.yHTML + '</span><br>'; } }).join(' '); } }

Or if you would rather replace the undefined with a dash for example:

legendFormatter(data: any) { if (data.x == null) { return data.series.map(element => { return '<span style="font-weight:bold; color:' + element.color + ';">' + '<div class="dygraph-legend-line" style="border-bottom-color:' + element.color + ';"></div>' + ' ' + element.labelHTML + '</span><br>'; }).join(' '); } else { return data.xHTML + '<br>' + data.series.map(element => { return '<span style="font-weight:bold; color:' + element.color + ';">' + '<div class="dygraph-legend-line" style="border-bottom-color:' + element.color + ';"></div>' + ' ' + element.labelHTML + ': ' + (element.yHTML ? element.yHTML : '-') + '</span><br>'; }).join(' '); } }

CameronSinclair84 avatar Oct 28 '19 12:10 CameronSinclair84

Well, I was also talking about specifying a function in options.legendFormatter to override the default one. I like your approach with the lines in the legend. Here is my simplified (improved?) version:

// options go here. See http://dygraphs.com/options.html
{
  legend: 'always',
  animatedZooms: true,
  title: 'dygraphs chart template',
  connectSeparatedPoints: true,
  legendFormatter: function(data) {
    return data.series.map(element => {
        return `<span style="font-weight:bold; color:${element.color};"><div class="dygraph-legend-line"></div> ${element.labelHTML}: ${element.yHTML || '-'}</span>`;
    }).join('<br/>');
  }
});

You can see it in action here: https://jsfiddle.net/6q3wkna4/

ALobpreis avatar Oct 28 '19 18:10 ALobpreis

PR was merged

mirabilos avatar Feb 17 '23 00:02 mirabilos