为什么我的 xAxis 在 d3 中没有排序?



昨天我发布了一个关于条形图的问题,我不知道如何按字母顺序排序。 @Mark_M非常友好地回答了我,并为我提供了一个通常应该完美工作的好解决方案。

这是片段:

var xAxis = d3.axisBottom(xScale).tickSize(0)
var sortBars = function() {
// Change domain based on sorted data
xScale.domain(data.sort(function(a, b) {
return  d3.ascending(a.Region, b.Region);
})
.map(function(d) {return d.Region})
)
// Redraw Rects with new position
svg.selectAll("rect")
.transition()
.duration(1000)
.attr("x", function(d, i) {return xScale(d.Region)})
// Redraw x Axis
axeX.transition()
.duration(1000)
.call(xAxis)

"rect"确实在排序,但是x轴(这里称为axeX(根本没有改变。似乎调用xAxis(最后一行(不起作用。

知道这里发生了什么吗?

这是完整的代码,排序部分在最后:

<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<title>D3 Test</title>
</head>
<body>
<style>
div.tooltip {position: absolute;            
text-align: center;            
width: none;                   
height: none;                  
padding: none;             
font: 12px futura;
color: thistle;        
background: none;  
border: 0px;       
border-radius: 8px;            
pointer-events: none;}
svg {background-color: none;}

.tooltip {font: 10px futura;
color: thistle;}

.axisX line{stroke: white;}
.axisX path{stroke: white;}
.axisX text{fill: black;}  
.axisY line{stroke: black;}
.axisY path{stroke: white;}

.horizontalGrid line {stroke: lightgrey;
stroke-opacity: 0;
shape-rendering: crispEdges;}
.horizontalGrid path {stroke-width: 0;}

</style>
<script type ="text/javascript" src = d3/d3.js></script>
<script>
//Variables; dimensions du canevas
var margin = {top: 40, right: 20, bottom: 130, left: 120},
svgWidth = 960 - margin.left - margin.right,
svgHeight = 400 - margin.top - margin.bottom,
barPadding = 2;
//Variables: domaines de l'Axe X et Y
var xScale = d3.scaleBand().range([0, svgWidth]).padding(0.1), //scaleBand pour des proportions
yScale = d3.scaleLinear().range([svgHeight, 0]); //scaleLinear pour des unités (noms, lettres)
//Variable: échelle de couleur divisée en 80 nuances entre deux couleurs
var colorScale = d3.scaleLinear().domain([0,80]).range(["white",  "mediumturquoise"]);
//Variable: création du canevas dans <body>
var svg = d3.select("body")
.append("svg")
.attr("width", svgWidth + margin.left + margin.right)
.attr("height", svgHeight + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Variable: petit encadré qui apparait au passage de la souris
var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("visibility", "hidden");
var absoluteView = false


//Variable: format des nombre lors de la transition de chargement des nombres -> https://github.com/d3/d3-format
var format = d3.format("d"); //d = notation décimale arrondie aux entiers

var xAxis = d3.axisBottom(xScale).tickSize(0)

//Biding: 
d3.csv("/Users/daumardlouis/Desktop/geid3.csv", function(error, data) {if (error) throw error;
data.forEach(function(d) {d.Classification = +d.Classification;});
xScale.domain(data.map(function(d) {return d.Region}));
yScale.domain([0, d3.max(data,function(d) {return d.Classification})]);
var xAxis = d3.axisBottom(xScale).tickSize(0) //marqueur d'échelle de taille 0

//Définition des barres
rect = svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) {return xScale(d.Region)})
.attr("width", svgWidth / data.length - barPadding)
.attr("y", svgHeight) // écart de l'axe Y = hauteur du canevas SVG
.attr("height", 0) // hauteur de départ des barres à 0 pour l'effet de transition
.attr("fill", function (d) {return colorScale (d.Classification)})
.style("opacity", 0.9)
.on("mouseover",function(d) {d3.select(this).style("fill", "thistle").style("opacity", 0.5); // rempli de couleur la barre au passage de la souris
div.transition() // affiche le div en 0.2 secondes avec opacité de .5
.duration(200)
.style("visibility", "hidden");
div.html(d.Classification) // affiche une donnée ou un texte dans le div
.style("left", (d3.event.pageX - 50) + "px") 
.style("top", (d3.event.pageY - 70) + "px"); // la hauteur du div par rapport à la souris (attention en html la hauteur est inversée)
if(!absoluteView) {
var xPos = parseFloat(d3.select(this).attr("x")) + 6;
var yPos = parseFloat(d3.select(this).attr("y")) + 2;
var height = parseFloat(d3.select(this).attr("height"));
svg.append("text")
.attr("x", xPos)
.attr("y", yPos - 10)
.attr("class", "tooltip")
.text(d.Classification)
.attr("fill", "thistle")};

})
.on("mouseout",function(d) {d3.select(this).transition().duration(150).style("fill", function (d) {return colorScale (d.Classification)}).style("opacity", 1); // renvoie la couleur initiale à la sortie de la souris
div.transition() // faire disparaitre la div après .5 secondes
.duration(200)
.style("visibility", "hidden")
svg.select(".tooltip").remove();
});
//Transition des barres (rect)
rect.transition()
.delay(1000)
.ease(d3.easePoly)
.duration(500)
.attr("y", function(d) {return yScale(d.Classification)})
.attr("height", function(d) {return svgHeight - yScale(d.Classification)}); 

//Transition: effet de chargement progressif des nombres 
var texte = svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(0) //texte à 0 au départ de la transition
.attr("x", function(d, i) {return 8 + i * (svgWidth / data.length)})
.attr("y", svgHeight) // commence à 0, cad à la hauteur du canevas 
.attr("fill", "thistle")
.attr("font-family", "futura")
.attr("font-size", "10px")
.transition()
.delay(function(d,i){return i *30}) //ajouter un délai décalé pour chaque élément de data
.ease(d3.easePoly)
.duration(900)
.attr("x", function(d, i) {return 8 + i * (svgWidth / data.length)})
.attr("y", function(d) {return yScale(d.Classification) + (yScale(svgHeight) / 16) })
.tween("text", function(d) {var that = d3.select(this),
i = d3.interpolateNumber(that.text(), d.Classification); //donner une val de départ et de fin
return function(t) {that.text(format(i(t)))}}) //retourne le texte au format défini plus haut
.transition()
.delay(function(d,i){return 500 + i * (-30)}) //delay de 500 + annulation du délai décalé
.style("opacity", 0);

//Axe X, son style et ses transitions
var axeX = svg.append("g")
.attr("transform", "translate(0," + svgHeight + ")")
.call(xAxis) 
.attr("class", "axisX") // récupère les indications de style de .axisX à l'interieur de la balise <style>. Utile pour changer la couleur de l'axe
.selectAll("text")
.attr("display", "true")
.attr("font-size", 2)
.attr("dx", "-4.8em")
.attr("dy", "4.15em")
.style("text-anchor", "end") //centre la fin du texte au milieu de chaque barre (rect)
.attr("transform", "rotate(-65)"); //effectue une rotation de -65°

axeX.transition()
.duration(500)
.delay(function(d,i){return i *30})
.attr("font-family", "futura", "Bold")
.attr("font-size", 10); //style de police de caractère


//Axe Y, son style et ses transitions
var axeY = svg.append("g")
.attr("class", "axisY")
.attr("transform", "translate(-5)")
.transition()
.duration(5000)
.call(d3.axisLeft(yScale).tickSize(3))
.selectAll("text")
.attr("transform", "translate(-5)")
.attr("font-family", "futura")
.attr("fill", "thistle");   //couleur de police de caractère

//Rajoute une légende à laxe Y
svg.append("g")
.append("text")
.attr("font-family", "futura")
.attr("font-size", 10)
.attr("transform", "rotate(-90)")
.attr("y", -48)
.attr("x", -68)
.style("text-anchor", "end")
.text("");

//Rajoute des lignes de fonds prolongeant l'axe Y
svg.selectAll("axisY")
.data(yScale)
.enter()
.append("line")
.attr("class", "horizontalGrid")
.attr("x1", 0)
.attr("x2", svgWidth)
.attr("y1", function(d){ return yScale(d);})
.attr("y2", function(d){ return yScale(d);});


//Title
title = svg.append("text")
.attr("x", (svgWidth / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.attr("font-family", "futura")
.style("fill", "#5a5a5a")
.text("Nombre d'observations par régions");
title.on("click", function () {sortBars()});

// Sorting
var sortBars = function() {xScale.domain(data.sort(function(a, b) 
{return  d3.ascending(a.Region, b.Region)}).map(function(d) {return d.Region}))
// Redraw Rects with new position
svg.selectAll("rect")
.transition()
.duration(1000)
.attr("x", function(d, i) {return xScale(d.Region)})
// Redraw x Axis
axeX.transition()
.duration(1000)
.call(xAxis)
}

});
</script>
<body>
</html>

您需要确保将正确的内容保存到axeX。由于已将selectAll("text")链接到它,因此axeX变量引用的是文本而不是轴。

请尝试以下操作:

//Axe X, son style et ses transitions
var axeX = svg.append("g")
.attr("transform", "translate(0," + svgHeight + ")")
.call(xAxis)         
.attr("class", "axisX") // récupère les indications de style de .axisX à l'interieur de la balise <style>. Utile pour changer la couleur de l'axe

axeX.selectAll("text")
.attr("display", "true")
.attr("font-size", 2)
.attr("dx", "-10px")
.attr("dy", "10px")
.style("text-anchor", "end") //centre la fin du texte au milieu de chaque barre (rect)
.attr("transform", "rotate(-65)") //effectue une rotation de -65°
.transition()
.duration(500)
.delay(function(d,i){return i *30})
.attr("font-family", "futura", "Bold")
.attr("font-size", 10); //style de police de caractère

我将dxdy属性更改为像素,因为 ems 使文本在刷新时跳来跳去。我不太确定如何使用ems获得您想要的效果。它们的值随字体大小而变化。

最新更新