2 votes

D3 - Graphique de zone avec une échelle logarithmique

Je tente de créer un graphique de zone avec un axe Y à échelle logarithmique. Ci-dessous, j'ai reproduit mon erreur en utilisant un code exemple que j'ai trouvé en ligne (mon code est un peu différent mais fonctionne essentiellement de la même manière).


J'ai commencé avec un graphique de base :
entrer la description de l'image ici

// définir les dimensions et marges du graphique
var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// ajouter l'objet svg au corps de la page
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

//Lire les données
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv",

  // En lisant le csv, je dois formater les variables:
  function(d){
    return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
  },

  // Maintenant je peux utiliser cet ensemble de données:
  function(data) {

    // Ajouter l'axe X --> c'est un format de date
    var x = d3.scaleTime()
      .domain(d3.extent(data, function(d) { return d.date; }))
      .range([ 0, width ]);
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    // Ajouter l'axe Y
    var y = d3.scaleLinear()
      .domain([1, d3.max(data, function(d) { return +d.value; })])
      .range([ height, 0 ]);
    svg.append("g")
      .call(d3.axisLeft(y));

    // Ajouter la ligne
    svg.append("path")
      .datum(data)
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", d3.line()
        .x(function(d) { return x(d.date) })
        .y(function(d) { return y(d.value) })
        )

})

Ensuite, j'ai essayé de le transformer en un graphique de zone avec une échelle logarithmique. Chaque fonctionnalité séparément fonctionne bien - mais combinées, elles cassent le graphique :
entrer la description de l'image ici

// définir les dimensions et marges du graphique
var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// ajouter l'objet svg au corps de la page
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

//Lire les données
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv",

  // En lisant le csv, je dois formater les variables:
  function(d){
    return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
  },

  // Maintenant je peux utiliser cet ensemble de données:
  function(data) {

    // Ajouter l'axe X --> c'est un format de date
    var x = d3.scaleTime()
      .domain(d3.extent(data, function(d) { return d.date; }))
      .range([ 0, width ]);
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    // Ajouter l'axe Y
    var y = d3.scaleLog()
      .domain([1, d3.max(data, function(d) { return +d.value; })])
      .range([ height, 0 ]);
    svg.append("g")
      .call(d3.axisLeft(y));

    // Ajouter la ligne
    svg.append("path")
      .datum(data)
      .attr("fill", "steelblue")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", d3.area()
        .x(function(d) { return x(d.date) })
        .y0(y(0))
        .y1(function(d) { return y(d.value) })
        )

})

La seule chose que j'ai modifiée est :

var y = d3.scaleLinear()
// en
var y = d3.scaleLog()

et

svg.append("path")
    .datum(data)
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 1.5)
    .attr("d", d3.line()
        .x(function(d) { return x(d.date) })
        .y(function(d) { return y(d.value) })
    )
// en
svg.append("path")
    .datum(data)
    .attr("fill", "steelblue")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 1.5)
    .attr("d", d3.area()
        .x(function(d) { return x(d.date) })
        .y0(y(0))
        .y1(function(d) { return y(d.value) })
    )

Je ne comprends pas ce qui ne va pas.

Tous les autres types d'échelles (linéaire, sqrt, pow) fonctionnent très bien lorsqu'ils sont combinés avec un graphique de zone. Le seul problème est avec l'échelle log. Et c'est littéralement la seule différence. Vous pouvez remplacer scaleLog par scaleSqrt et cela fonctionne...

Et je tiens à noter ici que mon échelle ne commence pas à 0 (log(0) est négatif infini). Donc ce n'est pas le problème.

2voto

Andrew Reid Points 16844

Le problème réside dans la façon dont vous définissez la ligne de base (y0) :

.attr("d", d3.area()
    .x(function(d) { return x(d.date) })
    .y0(y(0))
    .y1(function(d) { return y(d.value) })
)

Ici, vous utilisez 0 avec l'échelle logarithmique (y(0)), ce qui renverra bien sûr undefined. C'est pourquoi les autres échelles ne posent pas de problème mais l'échelle logarithmique en pose. Vous pourriez fournir une valeur très proche de zéro à l'échelle y, mais vous savez où la ligne de base devrait être : elle devrait être égale à la première valeur dans la plage de l'échelle y, il n'est pas nécessaire d'utiliser l'échelle pour déterminer cela :

  .y0(height)

Comme indiqué ci-dessous :

// définir les dimensions et marges du graphique
var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// ajouter l'élément svg au corps de la page
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

// Lire les données
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv",

  // Lors de la lecture du fichier csv, je dois formater les variables:
  function(d){
    return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
  },

  // Maintenant je peux utiliser cet ensemble de données:
  function(data) {

    // Ajouter l'axe X --> c'est un format de date
    var x = d3.scaleTime()
      .domain(d3.extent(data, function(d) { return d.date; }))
      .range([ 0, width ]);
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    // Ajouter l'axe Y
    var y = d3.scaleLog()
      .domain([1, d3.max(data, function(d) { return +d.value; })])
      .range([ height, 0 ]);
    svg.append("g")
      .call(d3.axisLeft(y));

    // Ajouter la ligne
    svg.append("path")
      .datum(data)
      .attr("fill", "steelblue")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", d3.area()
        .x(function(d) { return x(d.date) })
        .y0(height)
        .y1(function(d) { return y(d.value) })
        )

})

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X