I'm using the following code:
// Add title to y axis
svg.append("text")
.attr("x", -500)
.attr("y", -100)
.attr("text-anchor", "left")
.attr("transform", "rotate(270)")
.style("font-size", "16px")
.text("Test");
How can I have the text to be derived from the result of a function instead of being a string literal? Any help would be appreciated. Thanks.
You can just pass in a function .text, e.g. to set the text value to be the time at execution:
.text(function(){ return new Date(); })
If you want the text value to depend on data, then you need to bind data to the text element first.
Related
How to wrap long tick text in Observable using the Plot.plot function?
Here is an example with D3:
svg.select(".x_axis")
.call(xAxis.tickFormat(d3.timeFormat("%d-%m-%Y %H:%M:%S")))
.selectAll("text")
.call(function (t) {
t.each(function (d) {
var self = d3.select(this);
var s = self.text().split(' ');
self.text(null);
self.append("tspan")
.attr("x", 0)
.attr("dy", ".8em")
.text(s[0]);
self.append("tspan")
.attr("x", 0)
.attr("dy", "1.2em")
.text(s[1]);
})
});
It's not clear to me how to integrate this into the plot function. Can I use tickFormat for this?
We have been discussing this at https://github.com/observablehq/plot/issues/460 but there is no official support yet. The idea would be to consider newlines in the tick format to, well, create a new line, as we do in Plot.text. Drafts are available at https://github.com/observablehq/plot/pull/609 and https://github.com/d3/d3-axis/pull/83
With the hint "...do some kind of post processing on the svg that is returned by Plot..." from #Fil and some D3 code, I was now able to label the x-axis markers in two lines. Please check out the notebook data_plot at Observable.
I am trying to create a tooltip for my line chart that sends out dotted lines to the x and y axis (identical to this d3 n00b example, but my chart has multiple lines) http://www.d3noob.org/2014/07/my-favourite-tooltip-method-for-line.html
I have tried setting up two focus groups, tried adding the extra line info into the existing group, but all I can get is the date running on both lines but the dotted lines and data info only work on one.
Any help would be gratefully accepted.
Here is the chart with code underneath:
http://bl.ocks.org/anonymous/d1dbc221f95f6308b351
This is now fixed, renaming the two focus groups worked
Correct code:http://bl.ocks.org/anonymous/b77e904f34aa2162e1df
You are using the same variable for the two focus groups:
var focus = svg.append("g") // tooltip
.style("display", "none");
var focus = svg.append("g") // tooltip
.style("display", "none");
Name one variable focus1 and the other focus2 to make sure that they remain separate.
I would also recommend refactoring the code such that you don't have to call the exact same functions on both of these, once for the CPI line and once for RPIJ line. Instead, you should create a function which calls the required functions on a focus. You should pass the function which line to attach to and the correct focus group, i.e. focus1 and focus2.
Update for the edit:
As I understand it, you have now added text.y1, text.y2, text.y3 and text.y4 to both the focus groups and are effectively hiding the unnecessary information by setting the correct strokes to #fff here:
// place the value at the intersection RPIJ
focus2.append("text")
.attr("class", "y1")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "-.3em");
focus2.append("text")
.attr("class", "y2")
.attr("dx", 8)
.attr("dy", "-.3em");
// place the date at the intersection RPIJ
focus2.append("text")
.attr("class", "y3")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "1em");
focus2.append("text")
.attr("class", "y4")
.attr("dx", 8)
.attr("dy", "1em");
However, while doing it you have committed a couple of unique mistakes in each case.
For focus1, you do not create a text.y4 at all while for focus2, you update text.RPIJ instead of text.y3:
focus2.select("text.RPIJ")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.RPIJ) + ")")
.text("£" + d.RPIJ);
I'm basically using a modified version of : http://dimplejs.org/advanced_examples_viewer.html?id=advanced_bar_labels .
I'd like to be able to add for each value a border on the left as high as the value (with a specific color for that border).
I'm not really sure where to start for adding that.
Any ideas?
Thanks.
More details : This is what I'd like to obtain : https://dl.dropboxusercontent.com/u/2227188/Image%202.png - the border on the left is the issue. (jsfiddle.net/mkzTk/5/ this what I currently have which is pretty much what's in the example - I don't know where to start really for adding a border)
You could append a rectangle after drawing for each element of the series as follows:
mySeries.afterDraw = function (s, d) {
var shape = d3.select(s);
svg.append("rect")
.attr("x", shape.attr("x"))
.attr("y", shape.attr("y"))
.attr("height", shape.attr("height"))
.attr("width", "10px")
.style("fill", shape.style("stroke"))
.style("pointer-events", "none");
};
The example you mention already uses the afterDraw function so just add the contents above to the existing method for labelling.
It looks nice, here's an example:
http://jsbin.com/lorin/9/edit?js,output#J:L20
I would set up each bar + edge pair as its own group based on a certain data point, and then append two rect elements to that group. Differences in color can be used to give them their distinctive colors.
Your code would look something like this:
var monthBars = d3.selectAll('.monthBar') //These will be for each chart
.data(allMyData, idFunction) //Assign and key your data
.enter()
.append('g')
.classed('monthBar', true);
.each(function(d){
var taskGroups = d3.select(this).selectAll('.taskGroup')
.data(d.dataForThisMonth, taskIdFn)
.enter()
.append('g')
.classed('.taskGroup', true);
.attr('transform', ...) //Define the x and y positioning for the group
taskGroups.append('rect')
//Make this the 'body' rect with the text in it
taskGroups.append('rect')
//Make this the edge rect
})
I am drawing a piechart and i would like to have the labels with a break point. The labels are status and percentage which i get from csv file.
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
g.append("path")
.attr("d", arc)
.style("fill","#FFFFFF")
.transition()
.ease("bounce")
.duration(2000)
.delay(function(d, i) {return i * 1000;})
.style("fill", function(d) {return color(d.data.Source);});
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.html(function(d) {
if (eval(d.data.Components) >0)
{
return ((d.data.status) + " </br> " + " " + d.data.Percentage + "%");
}
});
An alternative to the tspan and text elements is the foreignObject. You can append a foreignObject, then append normal HTML. For you it would like something similar to this:
g.append("foreignObject")
.attr("width", "100px")
.attr("height", "100px")
.append("xhtml:div")
.html(function(d) {
return ((d.data.status) + " <br> " + " " + d.data.Percentage + "%");
});
I've found this approach easier to work with than tspan and text elements in the past, as it doesn't involve appending and positioning more elements than necessary.
The text element does not allow br tags in it.
From the docs:
Each ‘text’ element causes a single string of text to be rendered. SVG performs no automatic line breaking or word wrapping. To achieve the effect of multiple lines of text, use one of the following methods:
The author or authoring package needs to pre-compute the line breaks and use multiple ‘text’ elements (one for each line of text).
The author or authoring package needs to pre-compute the line breaks and use a single ‘text’ element with one or more ‘tspan’ child
elements with appropriate values for attributes ‘x’, ‘y’, ‘dx’ and
‘dy’ to set new start positions for those characters which start new
lines. (This approach allows user text selection across multiple lines
of text -- see Text selection and clipboard operations.)
Express the text to be rendered in another XML namespace such as XHTML [XHTML] embedded inline within a ‘foreignObject’ element. (Note:
the exact semantics of this approach are not completely defined at
this time.)
In your case, for example, you'll have to put d.data.status and d.data.Percentage + "%" in two different tspans in the text element and manually specify dy on them to align them vertically, like the examples shown here.
I would like to show a text on mouseover.
var circle = elemEnter.append("circle")
.attr("r", function(d){return d.r*2} )
.attr("dx", function(d){return d.x} )
.attr("stroke","gray")
.attr("fill", "#91c6ed")
.on("mouseover", function()
{d3.select(this).style("stroke", "#ff7f0e");
d3.select(this).style("stroke-width", "2px");
elemEnter.append("text")
.text(function(d){return d.name})})
.on("mouseout", function()
{d3.select(this).style("stroke", "gray");
d3.select(this).style("stroke-width", "1px");});
This piece of code works but show all the names on all the circles and when I try to replace
elemEnter.append("text").text(function(d){return d.name})
by
d3.select(this).append("text").text(d.name)
nothing happens.
I think it is possible to do it but I don't know what I'm doing wrong.
You can't append text to a circle. You need to start with a g and append the circle to the g and append the text to the g. Keep in mind that the g will not have cx/cy attributes and so you'll need to put that data into the following syntax:
.attr("transform", function (d) {return "translate("+d.X+","+d.Y")"})
If you're binding data, bind it to the g and then just naked append the circle and text to the g.