How to include HTML entity symbols with tickFormat? [duplicate] - javascript

I need to display micromoles per liter (µmol/L) in my chart's tickFormat, but when I pass in "µmol/L", it shows the characters "µ" instead of the symbol for mu. How do I get it to render the symbol?

In that case, you shouldn't use an HTML entity. Once you're dealing with an SVG , use this:
\u00B5
Check this snippet:
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 200);
var scale = d3.scaleLinear()
.range([40, 460])
.domain([0, 100]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d){ return d + "\u00B5mol/L"})
.ticks(5);
svg.append("g")
.attr("transform", "translate(0,100)")
.call(axis);
text { font-size: 14px;}
<script src="https://d3js.org/d3.v4.min.js"></script>

Related

Scaling y-axis appropriate to data in multiple line chart display

The multiple line chart example at https://www.d3-graph-gallery.com/graph/line_smallmultiple.html quite clearly provides the examples I need for what I'm trying to do...
except...
I need the y-axis scale for each of the charts to be appropriate for the data associated with the individual keys. As is, the example does d3.max on the entire data set, not the filtered data set controlling the individual lines.
I've tried various ways to apply the filter in the y-axis definition and can't get anything to work.
The closest I've been able to get is to make it use the max value from one of the specific keys for all the charts.
var y = d3.scaleLinear()
// .domain([0, d3.max(data, function(d) { return +d.n; })])
.domain([0, d3.max(data.filter(d => d.name === "Helen"), e => +e.n)])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y).ticks(5));
I think I want it to filter d.name against the CURRENT-CHART key (whatever it might be) rather than a specific one (like "Helen" above), but can't figure out how to do it. Is it some feature of nesting that I haven't found yet? Something amazingly simple that I can't see??
Any suggestions?
Thanks in advance
I have built a demo for you, i hope you are looking for something like this. Please let me know if there is any issue.
// set the dimensions and margins of the graph
var margin = {top: 30, right: 0, bottom: 30, left: 50},
width = 210 - margin.left - margin.right,
height = 210 - margin.top - margin.bottom;
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/5_OneCatSevNumOrdered.csv", function(data) {
// group the data: I want to draw one line per group
var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor
.key(function(d) { return d.name;})
.entries(data);
// What is the list of groups?
allKeys = sumstat.map(function(d){return d.key})
// Add X axis --> it is a date format
var x = d3.scaleLinear()
.domain(d3.extent(data, function(d) { return d.year; }))
.range([ 0, width ]);
// color palette
var color = d3.scaleOrdinal()
.domain(allKeys)
.range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf','#999999'])
// Add an svg element for each group. The will be one beside each other and will go on the next row when no more room available
var svg = d3.select("#my_dataviz")
.selectAll("uniqueChart")
.data(sumstat)
.enter()
.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 + ")")
.each(multiple);
svg
.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(3));
// Add titles
svg
.append("text")
.attr("text-anchor", "start")
.attr("y", -5)
.attr("x", 0)
.text(function(d){ return(d.key)})
.style("fill", function(d){ return color(d.key) })
function multiple(item) {
var svg = d3.select(this);
var y = d3.scaleLinear()
.domain([0, d3.max(item.values, function(d) { return +d.n; })])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y).ticks(5));
var line = d3.line()
.x(function(d) { return x(+d.year); })
.y(function(d) { return y(+d.n); });
// Draw the line
svg
.append("path")
.attr("fill", "none")
.attr("stroke", function(d){ return color(d.key) })
.attr("stroke-width", 1.9)
.attr("d", line(item.values))
}
})
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

Escape Characters in d3.js ticks

I need to display micromoles per liter (µmol/L) in my chart's tickFormat, but when I pass in "µmol/L", it shows the characters "µ" instead of the symbol for mu. How do I get it to render the symbol?
In that case, you shouldn't use an HTML entity. Once you're dealing with an SVG , use this:
\u00B5
Check this snippet:
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 200);
var scale = d3.scaleLinear()
.range([40, 460])
.domain([0, 100]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d){ return d + "\u00B5mol/L"})
.ticks(5);
svg.append("g")
.attr("transform", "translate(0,100)")
.call(axis);
text { font-size: 14px;}
<script src="https://d3js.org/d3.v4.min.js"></script>

How do I prevent graph elements from reaching the axis of my graph in D3 and scale properly?

I have currently have a quick test for a graph I'm about to create for website and I have made the most basic functionality. I have a graph, a 4 elements and an x and a y axis and a zoom functionality.
My problem lies in the fact that when I zoom on the graph, the elements are able to reach the axis and overlap it. I've pasted my source code below
//Setting generic width and height values for our SVG.
var margin = {top: 60, right: 0, bottom: 60, left: 40},
width = 1024 - 70 - margin.left - margin.right,
height = 668 - margin.top - margin.bottom;
//Other variable declarations.
//Creating scales used to scale everything to the size of the SVG.
var xScale = d3.scale.linear()
.domain([0, 1024])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([1, 768])
.range([height, 0]);
//Creates an xAxis variable that can be used in our SVG.
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//Zoom command ...
var zoom = d3.behavior.zoom()
.x(xScale)
.y(yScale)
.scaleExtent([1, 10])
.on("zoom", zoomTargets);
// The mark '#' indicates an ID. IF '#' isn't included argument expected is a tag such as "svg" or "p" etc..
var SVG = d3.select("#mainSVG")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
//Create background. The mouse must be over an object on the graph for the zoom to work. The rectangle will cover the entire graph.
var rect = SVG.append("rect")
.attr("width", width)
.attr("height", height);
//Showing the axis that we created earlier in the script for both X and Y.
var xAxisGroup = SVG.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var yAxisGroup = SVG.append("g")
.attr("class", "y axis")
.call(yAxis);
//This selects 4 circles (non-existent, there requires data-binding) and appends them all below enter.
//The amount of numbers in data is the amount of circles to be appended in the enter() section.
var circle = SVG
.selectAll("circle")
.data([40,100,400,1900])
.enter()
.append("circle")
.attr("cx",function(d){return xScale(d)})
.attr("cy",function(d){return yScale(d)})
.attr("r",20);
//Resets zoom when click on circle object. Zoom work now, should be changed to a button instead of click on circle though.
SVG.selectAll("circle").on("click", function() {
zoom.scale(1);
zoom.translate([0,0]);
zoomTargets();
});
function zoomTargets() {
SVG.select(".x.axis").call(xAxis);
SVG.select(".y.axis").call(yAxis);
SVG.selectAll("circle").attr("cx",function(d){return xScale(d)}).attr("cy",function(d){return yScale(d)});
}
function resetZoom() {
zoom.scale(1);
zoom.translate([0,0]);
zoomTargets();
}
I've tried using "append("g2") before creating a circle to I can make g2 smaller than the entire svg, but that doesn't seem to work. As far as I have understood, you can just append a new element inside your existing one. I'm guessing I'm wrong since it hasn't worked for me.
Thank you in advance for your help.
Leave a small gap between the most extreme data point and the axis. In particular, you may want the range of your domain to take the margins into account:
var xScale = d3.scale.linear()
.domain([0, 1024])
.range([0, width-margin.right]);
var yScale = d3.scale.linear()
.domain([1, 768])
.range([height, margin.bottom]);

Call axis function causing problems D3

I am just starting to learn D3, and have been following a tutorial to create this piece of code.
I created a couple of bars and intend to create an x axis for my graph.
The problem is when I add the ".call(xAxis)" to my canvas the browsers won't show me anything and I get the following error in the console:
Uncaught TypeError: Cannot call method 'copy' of undefined d3.min.js:5
(anonymous function) d3.min.js:5
(anonymous function) d3.min.js:3
R d3.min.js:1
da.each d3.min.js:3
n d3.min.js:5
da.call d3.min.js:3
(anonymous function)
Can anyone please help me with what's wrong? I really can't understand what's missing or what I'm doing wrong!
<!doctype html>
<html>
<head>
<title>Intro to D3</title>
<script src="d3.min.js"></script>
<head>
<body>
<script>
var width = 1024;
var height = 768;
var dataArray = [20, 40, 60, 120];
var xAxis = d3.svg.axis()
.scale(widthScale);
var widthScale = d3.scale.linear()
.domain([0, 120])
.range([0, width]);
var color = d3.scale.linear()
.domain([0, 120])
.range(["red", "blue"]);
var canvas = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(20, 0)")
.call(xAxis);
var bars = canvas.selectAll("rect")
.data(dataArray)
.enter()
.append("rect")
.attr("width", function(d){ return widthScale(d); })
.attr("height", 20)
.attr("fill", function(d){ return color(d); })
.attr("y", function(d, i){ return i*30; });
</script>
</body>
</html>
The problem is that you're assigning the scale to the axis before defining it. Doing it in this order works fine:
var widthScale = d3.scale.linear()
.domain([0, 120])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(widthScale);
You probably also want to append the bars to the SVG itself, not the g element that contains the axis. To do that, simply split the definition of canvas and the appending of the axis:
var canvas = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
canvas.append("g")
.attr("transform", "translate(20, 0)")
.call(xAxis);
Complete demo here.

Why doesn't my d3.js line chart work?

I'm currently learning d3.js, and as a task I am trying to build a line chart using a custom data source. For some reason, I can't get the line generator to work, and it seems like it can't create the d attribute for the path element. I don't seem to get any error messages either. Could someone please take a look?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
rect.bar {
//fill: steelblue;
}
.axis text {
font: 10px sans-serif;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v2.js"></script>
<script>
data = [{
name:'A Negative',
data:[{x:1346103936,y:0.10252502},{x:1346190336,y:0.10838352},{x:1346276736,y:0.11182367},{x:1346363136,y:0.1469633},{x:1346449536,y:0.108044505},{x:1346535936,y:0.10141762},{x:1346622336,y:0.13505103},{x:1346708736,y:0.11661343},{x:1346795136,y:0.09985885},{x:1346881536,y:0.10367505},{x:1346967936,y:0.12067748},{x:1347054336,y:0.1329808},{x:1347140736,y:0.14677866},{x:1347227136,y:0.14087029},{x:1347313536,y:0.13160454},{x:1347399936,y:0.1313771},{x:1347486336,y:0.14144897},{x:1347572736,y:0.15051538},{x:1347659136,y:0.15604788},{x:1347745536,y:0.14364798},{x:1347831936,y:0.12961338},{x:1347918336,y:0.11450371},{x:1348004736,y:0.11712107},{x:1348091136,y:0.12876798},{x:1348177536,y:0.10429894},{x:1348263936,y:0.110398784},{x:1348350336,y:0.10483569},{x:1348436736,y:0.14220005},{x:1348523136,y:0.11701017},{x:1348609536,y:0.12221267},{x:1348696576,y:0.11133491}]},{
name:'A Positive',
data:[{x:1346105088,y:0.20869565},{x:1346191488,y:0.14895636},{x:1346277888,y:0.2819277},{x:1346364288,y:0.19342105},{x:1346450688,y:0.35833332},{x:1346537088,y:0.19473684},{x:1346623488,y:0.23015076},{x:1346709888,y:0.15840708},{x:1346796288,y:0.23293903},{x:1346882688,y:0.21885246},{x:1346969088,y:0.22707888},{x:1347055488,y:0.26593626},{x:1347141888,y:0.22822087},{x:1347228288,y:0.24236642},{x:1347314688,y:0.17460318},{x:1347401088,y:0.19075145},{x:1347487488,y:0.1594203},{x:1347573888,y:0.13432837},{x:1347660288,y:0.0},{x:1347746688,y:0.18100129},{x:1347833088,y:0.1605938},{x:1347919488,y:0.12987013},{x:1348005888,y:0.12683824},{x:1348092288,y:0.15542522},{x:1348178688,y:0.13584906},{x:1348265088,y:0.14351852},{x:1348351488,y:0.1322314},{x:1348437888,y:0.13709678},{x:1348524288,y:0.17438692},{x:1348610688,y:0.0},{x:1348700160,y:0.18169399}]},{
name:'A Uncertain',
data:[{x:1346104576,y:0.04397342},{x:1346190976,y:0.044665344},{x:1346277376,y:0.049782943},{x:1346363776,y:0.051038638},{x:1346450176,y:0.050243802},{x:1346536576,y:0.03118218},{x:1346622976,y:0.04424348},{x:1346709376,y:0.04498049},{x:1346795776,y:0.04105231},{x:1346882176,y:0.04970384},{x:1346968576,y:0.045589853},{x:1347054976,y:0.046243627},{x:1347141376,y:0.05226451},{x:1347227776,y:0.047814183},{x:1347314176,y:0.04413969},{x:1347400576,y:0.03914877},{x:1347486976,y:0.042237047},{x:1347573376,y:0.054126237},{x:1347659776,y:0.04697353},{x:1347746176,y:0.04476943},{x:1347832576,y:0.042521983},{x:1347918976,y:0.05310476},{x:1348005376,y:0.059566505},{x:1348091776,y:0.043783925},{x:1348178176,y:0.043761015},{x:1348264576,y:0.046513315},{x:1348350976,y:0.0384231},{x:1348437376,y:0.04024283},{x:1348523776,y:0.040613018},{x:1348610176,y:0.04732518},{x:1348696576,y:0.06337391}]},{
name:'A Positive',
data:[{x:1346104320,y:0.109645985},{x:1346190720,y:0.092952825},{x:1346277120,y:0.10988262},{x:1346363520,y:0.12258253},{x:1346449920,y:0.12162819},{x:1346536320,y:0.11145041},{x:1346622720,y:0.17937773},{x:1346709120,y:0.1605882},{x:1346795520,y:0.15555955},{x:1346881920,y:0.15066825},{x:1346968320,y:0.17311412},{x:1347054720,y:0.21528025},{x:1347141120,y:0.20169735},{x:1347227520,y:0.15779452},{x:1347313920,y:0.1469917},{x:1347400320,y:0.15995567},{x:1347486720,y:0.17675863},{x:1347573120,y:0.14658852},{x:1347659520,y:0.2049946},{x:1347745920,y:0.15699232},{x:1347832320,y:0.14301357},{x:1347918720,y:0.1457654},{x:1348005120,y:0.1532571},{x:1348091520,y:0.17817244},{x:1348177920,y:0.13126957},{x:1348264320,y:0.12135763},{x:1348350720,y:0.14930858},{x:1348437120,y:0.14171022},{x:1348523520,y:0.12027296},{x:1348609920,y:0.13843122},{x:1348696576,y:0.15421592}]},{
name:'A Uncertain',
data:[{x:1346103936,y:0.046369042},{x:1346190336,y:0.042160377},{x:1346276736,y:0.06631727},{x:1346363136,y:0.043078776},{x:1346449536,y:0.049522486},{x:1346535936,y:0.041241966},{x:1346622336,y:0.041665666},{x:1346708736,y:0.0461979},{x:1346795136,y:0.044713285},{x:1346881536,y:0.041361943},{x:1346967936,y:0.051421918},{x:1347054336,y:0.04684727},{x:1347140736,y:0.048165746},{x:1347227136,y:0.053684916},{x:1347313536,y:0.05550549},{x:1347399936,y:0.05435959},{x:1347486336,y:0.04710294},{x:1347572736,y:0.05433203},{x:1347659136,y:0.06015368},{x:1347745536,y:0.047590178},{x:1347831936,y:0.045565397},{x:1347918336,y:0.056516618},{x:1348004736,y:0.06080917},{x:1348091136,y:0.068452686},{x:1348177536,y:0.049881306},{x:1348263936,y:0.04221391},{x:1348350336,y:0.0484556},{x:1348436736,y:0.0402809},{x:1348523136,y:0.058744337},{x:1348609536,y:0.054147776},{x:1348696576,y:0.056016088}]},{
name:'A Negative',
data:[{x:1346104832,y:0.25386313},{x:1346191232,y:0.14606741},{x:1346277632,y:0.17222223},{x:1346364032,y:0.19863014},{x:1346450432,y:0.17857143},{x:1346536832,y:0.14606741},{x:1346623232,y:0.12448133},{x:1346709632,y:0.12931034},{x:1346796032,y:0.25714287},{x:1346882432,y:0.22222222},{x:1346968832,y:0.1764706},{x:1347055232,y:0.28846154},{x:1347141632,y:0.1826923},{x:1347228032,y:0.2236842},{x:1347314432,y:0.091836736},{x:1347400832,y:0.25},{x:1347487232,y:0.17567568},{x:1347573632,y:0.15384616},{x:1347660032,y:0.0},{x:1347746432,y:0.23584905},{x:1347832832,y:0.13718411},{x:1347919232,y:0.0},{x:1348005632,y:0.13533835},{x:1348092032,y:0.0},{x:1348178432,y:0.06315789},{x:1348264832,y:0.0},{x:1348351232,y:0.14457831},{x:1348437632,y:0.13253012},{x:1348524032,y:0.1},{x:1348610432,y:0.0},{x:1348700160,y:0.29826254}]}];
var x = d3.scale.linear()
.range([0, "100%"])
.domain(d3.extent(data[0].data, function(d) { return d.x }));
var y = d3.scale.linear()
.domain([0, d3.max(data[0].data, function(d) { return d.y; })])
.range([0, "100%"]);
var line = d3.svg.line()
.x(function(d) { return x(d.x)})
.y(function(d) { return y(d.y)})
.interpolate("basis");
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", "500px");
var colors = d3.scale.category20().range();
var group = svg.selectAll("g").data(data);
group.enter().append("g")
.attr("fill", function(d, i) { return colors[i % colors.length]; })
.attr("opacity", "0.5").attr("stroke", "black").attr("stroke-width", "2");
group.selectAll("path")
.data(function(d) {return d.data})
.enter().append("path")
.attr("d", line)
.attr("class", "line");
</script>
I see a couple problems. The first is that the width and height attributes of SVG elements should be specified as unit-less numbers—always in pixels. This defines the coordinate space of the SVG element as well as its size on-screen. You can also set width and height style properties using px or percentages, but you should only do this in addition to setting the width and height attributes. The typical pattern is:
var width = 960,
height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
You might also want to look at the margin conventions example for more information.
The second thing I would change is to use this coordinate space to set the range of your scales, rather than using the percentage positioning:
var x = d3.scale.linear()
.domain(…)
.range([0, width]);
var y = d3.scale.linear()
.domain(…)
.range([height, 0]);
Note that the y-scale's range is inverted, so that y-0 is at the bottom of the chart rather than the default top. Again, see the conventions example for details.
Lastly, it looks like your x-values are seconds since UNIX epoch, so I would recommend converting your data to Date objects and then using a d3.time.scale. This makes it much easier to add an x-axis with date labels in the future. You can convert to dates as a preprocessing step like so:
data.forEach(function(series) {
series.data.forEach(function(d) {
d.x = new Date(d.x * 1000);
});
});

Categories

Resources