I'm using Donut3D.js library (which is based on D3.js chart library) (http://bl.ocks.org/NPashaP/9994181).
I've created a javascript event listener to listen for changes in a select option Html combo box control. Users select an option from the combo box and based on the selected option, the data for the 3d pie chart is fetched from a SQL Server database and the chart is re-drawn. However, my chart is not rendering, although when I'm in Firebug debug mode, it is re-drawn. I'm using Firefox and Firebug for debugging. My Web app is using an MVC pattern and C# programming language. Following are the code snippets:
In Partial View1:
<select id=hucDdl></select>
In Partial View2:
<script>
$(document).ready(function(){
//Event listener when selection changes
$("#hucDdl").change(function () {
//Get huc value
var huc;
if($("#hucDdl").val() != null){
huc = $("#hucDdl").val();
});
//Call function
ChangeData();
});
function ChangeData(){
<blockquote>var huc = $("#hucDdl").val();
var arr = [];
var lulcData = null;
//get data from SQL Server
$.ajax({<br/></blockquote>
url: "/Home/GetBaseLulcJson/",
type: "GET",
data: {huccode: huc},
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(result){
arr = result;
},
error: function(data){
}
})
lulcData = [
{ "label": "Cropland", "value": arr[0], "color": "#ffb3ba" },
{ "label": "Forest", "value": arr[1], "color": "#ffdfba" },
{ "label": "Pasture", "value": arr[2], "color": "#ffffba" },
{ "label": "Rangeland", "value": arr[3], "color": "#baffc9" },
{ "label": "Urban", "value": arr[4], "color": "#bae1ff" }
];
//Draw the 3d pie chart
Donut3D.draw("blulcpie", getData(), 90, 50, 90, 40, 30, 0);
function getData(){
<blockquote>return lulcData.map(function (d) {
return { label: d.label, value: +d.value, color: d.color };
});
}
});
</script>
The ChangeData() function is not firing on selection change.
Does anyone know how to get the chart to re-draw when data changes?
The data fetched from SQL Server are correct.
I'm just not sure what's causing the chart not to re-draw.
Solved this issue. I revised my codes as follows:
Index.cshmtl (main view):
<!--d3.js references-->
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="~/myscripts/donut3d.js" type="text/javascript"></script>
<div id="bLulc">
<label>Major Landuse</label>
#Html.Partial("~/Views/Shared/_BaseLanduse.cshtml")
</div>
Partial View1 (holds the select HTML control):
<select id = "hucDdl"></select>
Partial View2 (contains the 3d pie chart) "_BaseLanduse.cshtml":
<script type="text/javascript">
$(document).ready(function () {
//Set default array values for initial display on page load
var def_arr = [0.2, 80.3, 1.9, 16.9, 0.7];
var defData = [
{ "label": "Cropland", "value": def_arr[0], "color": "#ffb3ba" },
{ "label": "Forest", "value": def_arr[1], "color": "#ffdfba" },
{ "label": "Pasture", "value": def_arr[2], "color": "#ffffba" },
{ "label": "Rangeland", "value": def_arr[3], "color": "#baffc9" },
{ "label": "Urban", "value": def_arr[4], "color": "#bae1ff" }
];
//Define chart parameters
var margin = { top: 0, right: 20, bottom: 0, left: 20 }
var width = 180,
height = 230 - margin.bottom;
var svg = d3.select("#bLulc")
.append("svg")
.attr("width", width)
.attr("height", height);
svg.append("g")
.data([defData])
.attr("id", "blulcpie");
//Draw the chart
Donut3D.draw("blulcpie", defData, 90, 50, 90, 40, 30, 0);
//Define legend square size
var legendSpace = 4;
var rectSize = 8;
//Add legend
defData.forEach(function (d, i) {
svg.append("rect")
.attr("transform", "translate(0," + i * (rectSize + legendSpace) + ")")
.attr("class", "rect")
.attr("width", rectSize)
.attr("height", rectSize)
.attr("x", 50) //x-axis of rect
.attr("y", 130) //y-axis of rect
.style("stroke", "#000000")
.style("stroke-width", .25)
.style("fill", defData[i].color);
svg.append("text")
.attr("class", "legend")
.attr("x", rectSize + legendSpace)
.attr("y", (i * legendSpace) + (i * rectSize))
.attr("dx", 50) //x-axis of text
.attr("dy", 138) //y-axis of text
.style("font-size", "10px")
.text(defData[i].label);
});
//Event listener when huccode changes
$("#hucDdl").bind("mousedown mouseup", function () {
debugger;
//Get data from SQL Server via Controller
$.ajax({
url: "/Home/GetBaseLulcJson/",
type: "GET",
data: { huccode: $("#hucDdl").val() },
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
arr = result;
//alert(arr);
},
error: function (data) {
//alert(data);
}
})
var currData = [
{ label: "Cropland", value: arr[0], color: "#ffb3ba" },
{ label: "Forest", value: arr[1], color: "#ffdfba" },
{ label: "Pasture", value: arr[2], color: "#ffffba" },
{ label: "Rangeland", value: arr[3], color: "#baffc9" },
{ label: "Urban", value: arr[4], color: "#bae1ff" }
];
Donut3D.transition("blulcpie", currData, 90, 40, 30, 0);
});
});
Controller:
[HttpGet]
public JsonResult GetBaseLulcJson(string huccode)
{
//Returns single row, selected columns
var lulcBase = (from f in db.FractionsLulcs
where f.HUCCODE == huccode
select new
{
f.Cropland,
f.Forest,
f.Pasture,
f.Range,
f.Urban
}).SingleOrDefault();
//Convert to percentage
double?[] lulc = new double?[5];
lulc[0] = Math.Round(Convert.ToDouble(lulcBase.Cropland) * 100, 1);
lulc[1] = Math.Round(Convert.ToDouble(lulcBase.Forest) * 100, 1);
lulc[2] = Math.Round(Convert.ToDouble(lulcBase.Pasture) * 100, 1);
lulc[3] = Math.Round(Convert.ToDouble(lulcBase.Range) * 100, 1);
lulc[4] = Math.Round(Convert.ToDouble(lulcBase.Urban) * 100, 1);
return Json(lulc, JsonRequestBehavior.AllowGet);
}
Related
I have a nicely working drill down chart using d3.js, but I would like to add one (or more) deeper levels.
I can see how there's a level 0 (starting state) and a level 1 (one click deeper), but I can't seem to figure out how to implement that to a level 2 state (two clicks down).
Can somebody show me how to do that? I've got this so far: https://jsfiddle.net/yLsg841u/5/
<script type="text/javascript">
var salesData;
var chartInnerDiv = '<div class="innerCont" style="overflow: auto;top:100px; left: 400px; height:91% ; Width:100% ;position: relative;overflow: hidden;"/>';
var truncLengh = 30;
$(document).ready(function () {
Plot();
});
function Plot() {
TransformChartData(chartData, chartOptions, 0);
BuildPie("chart", chartData, chartOptions, 0)
}
function BuildPie(id, chartData, options, level) {
var xVarName;
var divisionRatio = 2.5;
var legendoffset = (level == 0) ? 0 : -40;
d3.selectAll("#" + id + " .innerCont").remove();
$("#" + id).append(chartInnerDiv);
chart = d3.select("#" + id + " .innerCont");
var yVarName = options[0].yaxis;
width = $(chart[0]).outerWidth(),
height = $(chart[0]).outerHeight(),
radius = Math.min(width, height) / divisionRatio;
if (level == 1) {
xVarName = options[0].xaxisl1;
}
else {
xVarName = options[0].xaxis;
}
var rcolor = d3.scale.ordinal().range(runningColors);
arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 200);
var arcOver = d3.svg.arc().outerRadius(radius + 20).innerRadius(radius - 180);
chart = chart
.append("svg") //append svg element inside #chart
.attr("width", width) //set width
.attr("height", height) //set height
.append("g")
.attr("transform", "translate(" + (width / divisionRatio) + "," + ((height / divisionRatio) + 30) + ")");
var pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return d.Total;
});
var g = chart.selectAll(".arc")
.data(pie(runningData))
.enter().append("g")
.attr("class", "arc");
var count = 0;
var path = g.append("path")
.attr("d", arc)
.attr("id", function (d) { return "arc-" + (count++); })
.style("opacity", function (d) {
return d.data["op"];
});
path.on("mouseenter", function (d) {
d3.select(this)
.attr("stroke", "white")
.transition()
.duration(200)
.attr("d", arcOver)
.attr("stroke-width", 1);
})
.on("mouseleave", function (d) {
d3.select(this).transition()
.duration(200)
.attr("d", arc)
.attr("stroke", "none");
})
.on("click", function (d) {
if (this._listenToEvents) {
// Reset inmediatelly
d3.select(this).attr("transform", "translate(0,0)")
// Change level on click if no transition has started
path.each(function () {
this._listenToEvents = false;
});
}
d3.selectAll("#" + id + " svg").remove();
if (level == 1) {
TransformChartData(chartData, options, 0, d.data[xVarName]);
BuildPie(id, chartData, options, 0);
}
else {
var nonSortedChart = chartData.sort(function (a, b) {
return parseFloat(b[options[0].yaxis]) - parseFloat(a[options[0].yaxis]);
});
TransformChartData(nonSortedChart, options, 1, d.data[xVarName]);
BuildPie(id, nonSortedChart, options, 1);
}
});
path.append("svg:title")
.text(function (d) {
return d.data["title"] + " (" + d.data[yVarName] + ")";
});
path.style("fill", function (d) {
return rcolor(d.data[xVarName]);
})
.transition().duration(1000).attrTween("d", tweenIn).each("end", function () {
this._listenToEvents = true;
});
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.style("opacity", 1)
.text(function (d) {
return d.data[yVarName];
});
count = 0;
var legend = chart.selectAll(".legend")
.data(runningData).enter()
.append("g").attr("class", "legend")
.attr("legend-id", function (d) {
return count++;
})
.attr("transform", function (d, i) {
return "translate(15," + (parseInt("-" + (runningData.length * 10)) + i * 28 + legendoffset) + ")";
})
.style("cursor", "pointer")
.on("click", function () {
var oarc = d3.select("#" + id + " #arc-" + $(this).attr("legend-id"));
oarc.style("opacity", 0.3)
.attr("stroke", "white")
.transition()
.duration(200)
.attr("d", arcOver)
.attr("stroke-width", 1);
setTimeout(function () {
oarc.style("opacity", function (d) {
return d.data["op"];
})
.attr("d", arc)
.transition()
.duration(200)
.attr("stroke", "none");
}, 1000);
});
var leg = legend.append("rect");
leg.attr("x", width / 2)
.attr("width", 18).attr("height", 18)
.style("fill", function (d) {
return rcolor(d[yVarName]);
})
.style("opacity", function (d) {
return d["op"];
});
legend.append("text").attr("x", (width / 2) - 5)
.attr("y", 9).attr("dy", ".35em")
.style("text-anchor", "end").text(function (d) {
return d.caption;
});
leg.append("svg:title")
.text(function (d) {
return d["title"] + " (" + d[yVarName] + ")";
});
function tweenOut(data) {
data.startAngle = data.endAngle = (2 * Math.PI);
var interpolation = d3.interpolate(this._current, data);
this._current = interpolation(0);
return function (t) {
return arc(interpolation(t));
};
}
function tweenIn(data) {
var interpolation = d3.interpolate({ startAngle: 0, endAngle: 0 }, data);
this._current = interpolation(0);
return function (t) {
return arc(interpolation(t));
};
}
}
function TransformChartData(chartData, opts, level, filter) {
var result = [];
var resultColors = [];
var counter = 0;
var hasMatch;
var xVarName;
var yVarName = opts[0].yaxis;
if (level == 1) {
xVarName = opts[0].xaxisl1;
for (var i in chartData) {
hasMatch = false;
for (var index = 0; index < result.length; ++index) {
var data = result[index];
if ((data[xVarName] == chartData[i][xVarName]) && (chartData[i][opts[0].xaxis]) == filter) {
result[index][yVarName] = result[index][yVarName] + chartData[i][yVarName];
hasMatch = true;
break;
}
}
if ((hasMatch == false) && ((chartData[i][opts[0].xaxis]) == filter)) {
if (result.length < 9) {
ditem = {}
ditem[xVarName] = chartData[i][xVarName];
ditem[yVarName] = chartData[i][yVarName];
ditem["caption"] = chartData[i][xVarName].substring(0, 10) + '...';
ditem["title"] = chartData[i][xVarName];
ditem["op"] = 1.0 - parseFloat("0." + (result.length));
result.push(ditem);
resultColors[counter] = opts[0].color[0][chartData[i][opts[0].xaxis]];
counter += 1;
}
}
}
}
else {
xVarName = opts[0].xaxis;
for (var i in chartData) {
hasMatch = false;
for (var index = 0; index < result.length; ++index) {
var data = result[index];
if (data[xVarName] == chartData[i][xVarName]) {
result[index][yVarName] = result[index][yVarName] + chartData[i][yVarName];
hasMatch = true;
break;
}
}
if (hasMatch == false) {
ditem = {};
ditem[xVarName] = chartData[i][xVarName];
ditem[yVarName] = chartData[i][yVarName];
ditem["caption"] = opts[0].captions != undefined ? opts[0].captions[0][chartData[i][xVarName]] : "";
ditem["title"] = opts[0].captions != undefined ? opts[0].captions[0][chartData[i][xVarName]] : "";
ditem["op"] = 1;
result.push(ditem);
resultColors[counter] = opts[0].color != undefined ? opts[0].color[0][chartData[i][xVarName]] : "";
counter += 1;
}
}
}
runningData = result;
runningColors = resultColors;
return;
}
chartOptions = [{
"captions": [{ "INDIA": "INDIA", "CANADA": "CANADA", "USA": "USA" }],
"color": [{ "INDIA": "#FFA500", "CANADA": "#0070C0", "USA": "#ff0000" }],
"xaxis": "Country",
"xaxisl1": "Model",
"yaxis": "Total"
}]
var chartData = [
{
"Country": "USA",
"Model": "Model 1",
"Total": 487
},
{
"Country": "USA",
"Model": "Model 2",
"Total": 185
},
{
"Country": "USA",
"Model": "Model 3",
"Total": 140
},
{
"Country": "USA",
"Model": "Model 4",
"Total": 108
},
{
"Country": "USA",
"Model": "Model 5",
"Total": 26
},
{
"Country": "USA",
"Model": "Model 6",
"Total": 106
},
{
"Country": "USA",
"Model": "Model 7",
"Total": 27
},
{
"Country": "USA",
"Model": "Model 8",
"Total": 44
},
{
"Country": "USA",
"Model": "Model 9",
"Total": 96
},
{
"Country": "INDIA",
"Model": "Model 1",
"Total": 411
},
{
"Country": "INDIA",
"Model": "Model 2",
"Total": 33
},
{
"Country": "INDIA",
"Model": "Model 3",
"Total": 32
},
{
"Country": "INDIA",
"Model": "Model 4",
"Total": 29
},
{
"Country": "INDIA",
"Model": "Model 5",
"Total": 29
},
{
"Country": "CANADA",
"Model": "Model 1",
"Total": 7
},
{
"Country": "CANADA",
"Model": "Model 2",
"Total": 20
},
{
"Country": "CANADA",
"Model": "Model 3",
"Total": 232
},
{
"Country": "CANADA",
"Model": "Model 4",
"Total": 117
}
];
I have tried adding one level.
Firstly, make sure you have json data for other level
Secondly, mention the 2nd level name in chartOptions as "xaxisl2":"YourLevelName"
Finally, add else if statement for (level==2) as follows:
TransformChartData(nonSortedChart, options, 2, d.data[xVarName]);
BuildPie(id, nonSortedChart, options, 2);
where xVarName=opts[0].xaxisl2;
I've recently begun learning D3.js and I am struggling to create a transition in a scatter plot with the following data:
var data = [
{"year" : "2004", "x":100, "y":300, "size": 2, "type": "A"},
{"year" : "2005", "x":200, "y":200, "size": 2, "type": "A"},
{"year" : "2006", "x":300, "y":100, "size": 2, "type": "A"},
{"year" : "2004", "x":150, "y":250, "size": 2.382450, "type": "B"},
{"year" : "2005", "x":150, "y":250, "size": 3.078548, "type": "B"},
{"year" : "2006", "x":150, "y":250, "size": 4.265410, "type": "B"}];
Where in the scatter plot there are 2 points (type A&B) and they change location (x&y) and size by year. I've created a fiddle where I try to nest the data and plot the points, but making the next step of using transition() function is confusing. More specifically, I am still declaring the whole data, but to make transitions work I only need part of the data.
The key to understand what you want lies here:
There are 2 points and they change location (x&y) and size by year
Therefore, this is clearly a XY problem. Your problem is not "how to transition with nested data". Your problem is "how to transition by year".
My proposed solution involves, first of all, dropping that nested array. You don't need that.
Instead, get all the years in the data...
var years = [...new Set(data.map(function(d) {
return d.year
}))];
..., filter the data by year...
var dataStart = data.filter(function(d) {
return d.year === years[0]
});
... and loop trough the years. Here, I'm using d3.interval():
var counter = 1;
var timer = d3.interval(transition, 1500);
function transition() {
var newData = data.filter(function(d) {
return d.year === years[counter]
});
svg.selectAll("circle").data(newData)
.transition()
.duration(1000)
.attr("cx", function(d) {
console.log(d)
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.size * 10;
});
counter += 1;
if (counter === 3) {
timer.stop()
}
}
Here is the demo:
var data = [{
"year": "2004",
"x": 100,
"y": 100,
"size": 2,
"type": "A"
}, {
"year": "2005",
"x": 200,
"y": 180,
"size": 2,
"type": "A"
}, {
"year": "2006",
"x": 300,
"y": 50,
"size": 2,
"type": "A"
}, {
"year": "2004",
"x": 150,
"y": 150,
"size": 2.382450,
"type": "B"
}, {
"year": "2005",
"x": 150,
"y": 50,
"size": 3.078548,
"type": "B"
}, {
"year": "2006",
"x": 150,
"y": 100,
"size": 4.265410,
"type": "B"
}];
var width = 400,
height = 200;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var years = [...new Set(data.map(function(d) {
return d.year
}))];
var dataStart = data.filter(function(d) {
return d.year === years[0]
});
var cell = svg.selectAll("circle")
.data(dataStart);
cell.enter()
.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.size * 10;
});
var counter = 1;
var timer = d3.interval(transition, 1500);
function transition() {
var newData = data.filter(function(d) {
return d.year === years[counter]
});
svg.selectAll("circle").data(newData)
.transition()
.duration(1000)
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.size * 10;
});
counter += 1;
if (counter === 3) {
timer.stop()
}
}
<script src="https://d3js.org/d3.v4.min.js"></script>
I have a d3 force layout with a line connecting a character. My code currently looks something like this...
edges.selectAll("line")
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; });
<g class="edge"><line x1="183.7429436753079" y1="-3182.732396966405" x2="-224.94046319279028" y2="-2920.273406745797" style="stroke: rgb(255, 255, 255); stroke-width: 1px;"></line><text fill="white" x="-20.59875975874118" y="-3051.502901856101"></text></g>
<g class="node" transform="translate(4109.590685978889,2004.5469511133144)"><text fill="white"></text><text fill="white" y="15">Interior</text></g>
When I use this I see something like the following...
as you can see the relations all meet at the bottom, however, I want them to meet on the left. For this I figure I need to change to something like...
edges.selectAll("line")
.attr("x1", function (d) { return d.source.x+r; })
.attr("y1", function (d) { return d.source.y-r; })
.attr("x2", function (d) { return d.target.x+r; })
.attr("y2", function (d) { return d.target.y-r; });
Where r is the radius. Short of keeping an array with the widths of all nodes, is there a way to grab the source and target's width?
You can add the BBox onto the node data as a reference while adding the text elements to the document. If you add the nodes first, followed by the links, you can transfer information from the former to the later by adding a reference to the node elements onto the data elements. You can also add any other helpful positioning state that you might need on data array elements. After that you can access whatever you need in the force tick call-back via d.source and d.target.
Using font awesome fonts I noticed that the bounding box took at least one animation cycle to evolve to the correct shape so I had to add an animation timer to run a few (10) times after initial rendering to update the bounding box a few times and reposition the glyphs to be properly centered.
Edit
Made the bounding box adjustment permanent (not just run 10 times) to work around a bug in webkit whereby the glyph alignment breaks on zoom events. This however caused problems in moz so need to find another way to fix the zoom bug in webkit.
Note
Referencing the svg element that the data is bound to, from that data element, creates a circular reference. So special care needs to be taken to break the reference chain. In the example below, the BBox reference is deleted after the required state has been copied onto the data elements.
Working example
//debug panel/////////////////////////////////////////////////////////////////////////////
d3.select("#update").on("click", (function() {
var dataSet = false;
return function() {
refresh(dataSets[(dataSet = !dataSet, +dataSet)])
}
})());
var alpha = d3.select("#alpha").text("waiting..."),
cog = d3.select("#wrapAlpha").insert("i", "#fdg").classed("fa fa-cog fa-spin", true),
fdgInst = d3.select("#fdg");
elapsedTime = ElapsedTime("#panel", {margin: 0, padding: 0})
.message(function (id) {
return 'fps : ' + d3.format(" >8.3f")(1/this.aveLap())
});
elapsedTime.consoleOn = false;
//////////////////////////////////////////////////////////////////////////////////
var dataSets = [
{
"nodes": [
{"name": "node1", "content": "the first Node"},
{"name": "node2", "content": "node2"},
{"name": "node3", "content":{"fa": "fa/*-spin*/", text: "\uf013"}},
{"name": "node4", "content":{"fa": "fa/*-spin*/", text: "\uf1ce"}}
],
"edges": [
{"source": 2, "target": 0},
{"source": 2, "target": 1},
{"source": 2, "target": 3}
]
},
{
"nodes": [
{"name": "node1", "content": "node1"},
{"name": "node2", "content":{"fa": "fa/*-spin*/", text: "\uf1ce"}},
{"name": "node3", "content":{"fa": "fa/*-spin*/", text: "\uf013"}},
{"name": "node4", "content": "4"},
{"name": "node5", "content": "5"},
{"name": "node6", "content": "6"}
],
"edges": [
{"source": 2, "target": 0},
{"source": 2, "target": 1},
{"source": 2, "target": 3},
{"source": 2, "target": 4},
{"source": 2, "target": 5}
]
}
];
var refresh = (function(){
var instID = Date.now(),
height = 160,
width = 500,
force = d3.layout.force()
.size([width, height])
.charge(-1000)
.linkDistance(50)
.on("end", function(){cog.classed("fa-spin", false); elapsedTime.stop()})
.on("start", function(){cog.classed("fa-spin", true); elapsedTime.start()});
return function refresh(data) {
force
.nodes(data.nodes)
.links(data.edges)
.on("tick", (function(instID) {
return function(e) {
elapsedTime.mark();
alpha.text(d3.format(" >8.4f")(e.alpha));
fdgInst.text("fdg instance: " + instID);
lines.attr("x1", function(d) {
return d.source.x + d.source.cx + d.source.r;
}).attr("y1", function(d) {
return d.source.y + d.source.cy;
}).attr("x2", function(d) {
return d.target.x + d.target.cx;
}).attr("y2", function(d) {
return d.target.y + d.target.cy;
});
node.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")"
});
}
})(instID))
.start();
var svg = d3.select("body").selectAll("svg").data([data]);
svg.enter().append("svg")
.attr({height: height, width: width});
var lines = svg.selectAll(".links")
.data(linksData),
linesEnter = lines.enter()
.insert("line", d3.select("#nodes") ? "#nodes" : null)
.attr("class", "links")
.attr({stroke: "steelblue", "stroke-width": 3});
var nodes = svg.selectAll("#nodes").data(nodesData),
nodesEnter = nodes.enter().append("g")
.attr("id", "nodes"),
node = nodes.selectAll(".node")
.data(id),
newNode = node.enter().append("g")
.attr("class","node")
.call(force.drag);
newNode.append("text")
.attr({class: "content", fill: "steelblue"})
newNode.insert("circle", ".node .content");
var glyphs = node.select("text")
.each(function(d) {
var node = d3.select(this);
if(d.content.fa)
node.style({'font-family': 'FontAwesome', 'font-size': '32px', 'dominant-baseline': 'central'})
.classed(d.content.fa, true)
.text(d.content.text);
else
node.text(d.content)
.attr({"class": "content", style: null});
})
.call(getBB),
backGround = node.select("circle").each(function(d) {
d3.select(this).attr(makeCircleBB(d))
}).style({"fill": "red", opacity: 0.8});
(function(id){
//adjust the bounding box after the font loads
var count = 0;
d3.timer(function() {
console.log(id);
glyphs.call(getBB);
backGround.each(function(d) {
d3.select(this).attr(makeCircleBB(d))
});
return /*false || id != instID*/++count > 10; //needs to keep running due to webkit zoom bug
})
})(instID);
lines.exit().remove();
node.exit().remove();
function nodesData(d) {
return [d.nodes];
}
function linksData(d) {
return d.edges;
}
};
function getBB(selection) {
this.each(function(d) {
d.bb = this.getBBox();
})
}
function makeCircleBB(d, i, j) {
var bb = d.bb;
d.r = Math.max(bb.width, bb.height) / 2;
delete d.bb; //plug potential memory leak!
d.cy = bb.height / 2 + bb.y;
d.cx = bb.width / 2;
return {
r: d.r, cx: d.cx, cy: d.cy, height: bb.height, width: bb.width
}
}
function id(d) {
return d;
}
})();
refresh(dataSets[0]);
svg {
outline: 1px solid #282f51;
pointer-events: all;
overflow: visible;
}
g.outline {
outline: 1px solid red;
}
#panel div {
display: inline-block;
margin: 0 .25em 3px 0;
}
#panel div div {
white-space: pre;
margin: 0 .25em 3px 0;
}
div#inputDiv {
white-space: normal;
display: inline-block;
}
.node {
cursor: default;
}
.content {
transform-origin: 50% 50%;
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://rawgit.com/cool-Blue/d3-lib/master/elapsedTime/elapsed-time-1.0.js"></script>
<div id="panel">
<div id="inputDiv">
<input id="update" type="button" value="update">
</div>
<div id="wrapAlpha">alpha:<div id="alpha"></div></div>
<div id="fdg"></div>
</div>
<div id="viz"></div>
I have the following line chart: http://jsfiddle.net/cp3fV/2/
var data = [
{
"days_to_expiry": 0,
"close": "7.1120000000"
},
{
"days_to_expiry": 1,
"close": "8.4580000000"
},
{
"days_to_expiry": 2,
"close": "7.2830000000"
},
{
"days_to_expiry": 3,
"close": "12.2820000000"
},
{
"days_to_expiry": 4,
"close": "7.1820000000"
}
]
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({left: 100, right:50})
.useInteractiveGuideline(true)
.transitionDuration(350)
.showLegend(false)
.showYAxis(true)
.showXAxis(true)
//.forceY([0, 19])
.y(function (d) { return d.close })
.x(function (d) { return d.days_to_expiry })
;
console.log(data);
chart.xAxis
.axisLabel('Date')
.ticks(10);
chart.yAxis
.axisLabel('Close')
.tickFormat(d3.format('.03f'));
var testData = [{key:"Test", color: '#2ca02c', values: data}];
d3.select('#chart svg')
.datum(testData)
.call(chart);
nv.utils.windowResize(function() { chart.update() }); // Update on resize
return chart;
});
I just want to order the Y axis from minimum to maximum. It works fine if all the values are <10
I know I can use forceY(min, max) but I don't want to calculate the minimum every time(I'm planning to use AJAX to update the chart)
It works if you use the numbers as numbers and not as strings:
data.forEach(function(d) { d.close = +d.close; });
Complete example here.
I am having an issue using a line chart getting the calculated labels in the x-axis to space properly. If I want to have 5 data points with a few missing (e.g. [1,50.1],[2,49.2],[5,20.4],[6,17],[7,23.3]), the x-axis will show 1 then 2 then a space where 3 and 4 should have been then 5, 6, and 7. What I would like is to have the 5th data point beside the 2nd data point (in the position where the 3rd data point would ideally be). Basically I am trying to hide a data point yet keep the x-axis value in the grid.
Any assistance is much appreciated.
Try this:
<script type="text/javascript">
$(document).ready(function () {
var plot2 = $.jqplot('chart2', [[[1,50],[2,49],[5,20],[6,17],[7,23]]], {
title: 'Plot',
axesDefaults: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
},
axes: {
xaxis: {
label: "X Axis",
pad: 0,
ticks:[1,2,5,6,7] //you can create this dynamically
},
yaxis: {
label: "Y Axis"
}
}
});
});
UPDATE:
<script type="text/javascript">
$(document).ready(function () {
var producciones = [];
for (var i = 0; i < 2000; i++) { producciones.push(new Number(i),new Number(i)) }
var plot2 = $.jqplot('chart2', [producciones], {
title: 'Plot',
axesDefaults: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
},
axes: {
xaxis: {
label: "X Axis",
pad: 0,
numberTicks: 100
},
yaxis: {
label: "Y Axis"
}
}
});
});