Is it possible to create a d3.js axis and have there be no tick marks and no numbering scheme? Basically, can I make the axis invisible? I'm using the code below to create my axes:
svg.selectAll("axis")
.data(d3.range(angle.domain()[1]))
.enter().append("g")
.attr("class", "axis")
.attr("transform", function(d) { return "rotate(" + angle(d) * 180 / Math.PI + ")"; })
.call(d3.svg.axis()
.scale(radius.copy().range([0,0]))
.ticks(1)
.orient("left"))
.append("text")
.style("color", "white")
.attr("y",
function (d) {
if (window.innerWidth < 455){
console.log("innerWidth less than 455: ",window.innerWidth);
return -(0);
}
else{
console.log("innerWidth greater than 455: ",window.innerWidth);
return -(0);
}
})
.attr("dy", "0em");
If you don't want your axis to be visible, just don't draw them (basically comment out this code).
If you really just want to turn them white, you can use the following classes:
.axis line, .axis text, .axis path {
color: white;
}
This would be the easiest way to manipulate them to turn them 'on' and 'off'. Also, if you ever need to figure out how to style a d3 diagram, you can navigate through the SVG just like you do html and style with CSS the same way too.
For example, here is the SVG for the tick marks in the axis.
<line class="tick" y2="6" x2="0"></line>
You can see that I targeted the element (line) but you could also target (.tick) as well.
Related
I am using this Bar Chart on D3 Observable. I need to change the font-size and color of the labels on the axes/ticks. In the previous D3 approach you could simply do this in CSS like:
text {
fill : white;
font-size : 22px;
}
But Observable doesn't provide the usual HTML file for placing CSS.
If you look at the file there doesn't appear to be any text appended, although in inspect element you can see the labels are indeed "text"
I tried adding style to the appended g:
svg.append("g")
.style("fill", "white")
.call(xAxis);
But to no avail.
In an Observable notebook you can add your CSS using the html method with a template literal, like this:
html`<style>
text {
fill : white;
font-size : 22px;
}
</style>`
Just create a new cell (clicking the + sign) and copy/paste the snippet above.
You can style the text on this chart in Observable by looking for the cells containing the XAxis and yAxis.
and...
Below the .attr("transform") lines add this line for font size:
.style("font-size", "22px")
...and this line for color:
.attr("color", "red")
Not sure why D3 decided to change .style("fill" to .attr("color"
Your cells should now look like this:
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.style("font-size", "22px")
.attr("color", "red")
.call(d3.axisBottom(x)
.tickSizeOuter(0))
and...
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.style("font-size", "22px")
.attr("color", "red")
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
Result:
I am trying to get a little percent sign superscript.
I found and example which works but not percent
var svgText = svg.append('text').text('This is a test : mm²')
Is there a way that I could do the same with the percent?
.text(function (d) {return d.site + 'mm²';});
to make 75 % superscripted
Why not use a tspan? This will allow you to format any text how you want, superscript or otherwise, no matter if there is a unicode superscript symbol you can use:
Within a element, text and font properties and the current text
position can be adjusted with absolute or relative coordinate values
by including a <tspan> element. (MDN)
There are a few approaches you could take in this regard, but if you can extract the text that needs to be superscript (or generate it on the fly), then you can create the superscript and regular text relatively easly. Below I use a tspan to hold the regular text and another to hold the superscript:
var svg = d3.select("body").append("svg");
var data = [
{text: "Here's some normal text", super:"Here's superscript"},
{text:"Some text", super:"α,β,γ,%,!,1,2,3"}
];
var text = svg.selectAll()
.data(data)
.enter()
.append("text")
.attr("x", 10)
.attr("y", function(d,i) { return i * 20 + 20; });
// Main content:
text.append("tspan")
.text(function(d) { return d.text; })
.attr("font-size", 14)
// Superscript content:
text.append("tspan")
.text(function(d) { return " " +d.super; })
.attr("dy",-5)
.attr("font-size",11)
<script src="https://d3js.org/d3.v5.min.js"></script>
With a bit of string manipulation you could use this pattern without pre-existing properties for each text string (below I use only one text span with normal text just being added as normal):
var svg = d3.select("body").append("svg");
var data = [
"Length is 10px - 10%",
"Height is 20px - 30%"
];
var text = svg.selectAll()
.data(data)
.enter()
.append("text")
.attr("x", 10)
.attr("y", function(d,i) { return i * 20 + 20; })
.text(function(d) {
return d.split("-")[0];
});
// Superscript content:
text.append("tspan")
.text(function(d) { return d.split("-")[1]; })
.attr("dy",-5)
.attr("font-size",11)
<script src="https://d3js.org/d3.v5.min.js"></script>
The tspan approach is useful in that it maintains text position, which is easier to manage than placing multiple text elements where the position of each depends on the width of other text elements.
Since there is no superscript character for % in unicode, you have to take the approach laid out by Andrew Reid in his answer. Although there is nothing wrong with his approach, you could make your life a little easier and the code a bit more readable by using the baseline-shift attribute of the <tspan>:
The baseline-shift attribute allows repositioning of the dominant-baseline relative to the dominant-baseline of the parent text content element. The shifted object might be a sub- or superscript.
Since you can nest the tspan inside your normal text, there is no need to explicitly position the element. Your code could be something along the following lines:
<text x="100" y="100">
Test
<tspan baseline-shift="super" font-weight="bolder" font-size="62%">75%</tspan>
</text>
Have a look at the following snippet for a working D3 demo:
var svg = d3.select("body").append("svg");
var text = svg
.append("text")
.attr("x", 50)
.attr("y", 50)
.text("Test");
// Superscript
text.append("tspan")
.text("75%")
.attr("baseline-shift", "super")
.attr("font-size", "62%")
.attr("font-weight", "bolder");
<script src="https://d3js.org/d3.v5.js"></script>
I am trying to add the label and icon in this codepen as per this example Labeled Force Layout
In my restart method, I have added the code
node.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8).attr("y", -8).attr("width", 16).attr("height", 16)
.on("mousedown", mousedownNode);
node.append("text").attr("dx", 12).attr("dy", ".35em").text(function(d) { return d.id });
after my existing code :
node.enter().insert("circle", ".cursor")
.attr("class", "node").attr("r", 10).on("mousedown", mousedownNode);
I understand that I am making the node as circle first then trying to add an icon to it, which is the issue here but I am not sure how to fix it.
You cannot append a <text> element to a <circle> element.
The idiomatic solution here is converting node into a group selection, just like Mike Bostock has in the example you shared:
node.enter().insert("g", ".cursor")
.attr("class", "node");
Then, appending the circles and the texts to node:
node.append("circle")
.attr("r", 10)
.on("mousedown", mousedownNode);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) {
return d.id
});
And, finally, changing the tick function:
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
});
Here is the updated CodePen: https://codepen.io/anon/pen/VBepoo?editors=0010
Of course, this is just a quick refactor: you have to change other parts of your code for having node as a group selection.
Thank you Gerardo for this very helpful CodePen entry. Apparently, the CSS overrides the JS and must be modified in order for the icon to appear, for example:
From: .node { fill: #000; }
To: .node { fill: none; stroke: <some color so the labels appear>;}
My update of your update on CodePen
I tried to make a straight line with this:
enter.append('line')
.attr('class', 'lineClass')
.style("stroke", "blue")
.style("stroke-width", "1.5px;")
.attr('x1', function(d) { return 500; })
.attr('y1', function(d) { return 50; })
.attr('x2', function(d) { return 800; })
.attr('y2', function(d) { return 40; });
The line attrs will be actual functions with data. Look at my image, why is the line crooked? If there is no problem with the code, do you have any ideas as to what could be causing this?
The reason is you are drawing same line again and again on the same x1/x2/y1/y2 for dataset.
This will make your line crooked:
var svg = d3.select('svg');
var dataSet = [10,20,30,20,30,20,30,20,30,20,30,20,30,20,30,20,30];//many data 17 times you will draw line.
var myLine = svg.selectAll('line')
.data(dataSet)
.enter()
.append('line')
.style("stroke", "blue")
.attr('x1', function(d) { return 100; })
.attr('y1', function(d) { return 200; })
.attr('x2', function(d) { return 300; })
.attr('y2', function(d) { return 40; });
Working example here
Now the crookedness will go coz you are making a single line on the x1/x2/y1/y2
var svg = d3.select('svg');
var dataSet = [10];//you will draw line ones
var myLine = svg.selectAll('line')
.data(dataSet)
.enter()
.append('line')
.style("stroke", "blue")
.attr('x1', function(d) { return 100; })
.attr('y1', function(d) { return 200; })
.attr('x2', function(d) { return 300; })
.attr('y2', function(d) { return 40; });
Working example here
So in short you should not be drawing same line over and over again...
Hope this helps!
First of all, this is not to blame on D3 at all. This effect is known as aliasing and is very common to all sorts of computer graphics. There is a vast arsenal of countermeasures against it, which are referred to as anti-aliasing. However, it will always be a trade-off between precision and aesthetics.
For SVGs you are — at least to a certain degree — able to control the way the browser or any other user agent deals with this by setting the shape-rendering attribute. Have a look at this example which demonstrates the effect:
line {
stroke: blue;
stroke-width: 1;
}
text { font-family: monospace; }
<svg width="500" height="210" xmlns="http://www.w3.org/2000/svg">
<text y="25">auto</text>
<line shape-rendering="auto" x1="150" y1="20" x2="450" y2="30" />
<text y="75">optimizeSpeed</text>
<line shape-rendering="optimizeSpeed" x1="150" y1="70" x2="450" y2="80" />
<text y="125">crispEdges</text>
<line shape-rendering="crispEdges" x1="150" y1="120" x2="450" y2="130" />
<text y="175">geometricPrecision</text>
<line shape-rendering="geometricPrecision" x1="150" y1="170" x2="450" y2="180" />
</svg>
Because line #3 having shape-rendering="crispEdges" closely resembles your screenshot, this is most likely the cause of your problem. For this value the SVG spec states:
To achieve crisp edges, the user agent might turn off anti-aliasing for all lines...
To get a smoother line, try setting another value for this property. Please note, that this property is inherited. There is no need to repeat yourself setting this on every element. You might just as well define this somewhere up the DOM hierarchy or even on the root SVG element itself. Additionally, you may opt for setting this via a CSS rule instead of specifying it as an attribute to an element.
The line in your picture is not crooked - it is straight between the points (500,50) and (800,40).
I am trying to plot a customized yAxis using D3.js. My ideal result should be like this: JSFiddle.
But I haven't found the way to export the SVG image together with CSS styles. So I would like to move the styles to the SVG elements:
var yNode = svg.append("g")
.style("fill", "none")
.style("stroke", "#000")
.attr("transform", "translate(" + left + ",0)")
.attr("class", "axis")
.call(yAxis);
yNode.selectAll('text')
.style('font-size', '11px')
.style('font-family', 'Lucida Console');
The code is here: JSFiddle.
All the styles are the same. But somehow the yAxis label of the later one becomes blur and bold. How to fix it? Thanks.
Here it is : JsFiddle
You selected the whole axis dom element and applied the fill: none and stroke: black to it. The axis contains both: the path and the text, and both are going to be affected by the stroke. That's why your text is stroked.
So I commented out the fill & stroke here
var yNode = svg.append("g")
//.style("fill", "none")
//.style("stroke", "#000")
.attr("transform", "translate(" + left + ",0)")
//.attr("class", "axis")
.call(yAxis);
Selected the path and added the fill and stroke styles
yNode.select('path')
.style("fill", "none")
.style("stroke", "#000");