vis.js Level sorting in Hierarchical Layout - javascript

I have a fairly simple hierarchical structure of nodes, but when vis.js draws them, the order of nodes on each level doesn't make much sense - there are a lot of crossed edges (screenshot: Default Layout )
I am hoping to get a layout similar to that given here:
Expected Layout
My vis.js options are as follows;
{
"layout": {
"hierarchical": {
"direction": "LR",
"sortMethod": "directed",
"nodeSpacing": 200,
"treeSpacing": 400
}
},
"edges": {
"smooth": {
"type": "continuous"
}
},
"nodes": {
"physics": false
}
};
What is the best method to produce this sorted layout?

I suggest your try enabling physics, which will sort out the edges crossing, etc.
However, in hierarchical layout, it's a good idea to disable the engine once it's done the first iterations by catching the 'stabilizationIterationsDone' event as follows:
network.on("stabilizationIterationsDone", function(){
network.setOptions( { physics: false } );
});

you should remove the quotation marks. these are object's properties, not strings. it should look like this:
layout: {
hierarchical: {
direction: "LR",
sortMethod: "directed",
nodeSpacing: 200,
treeSpacing: 400
}
},
edges: {
smooth: {
type: "continuous"
}
},
nodes: {
physics: false
}

Related

C3 and React - DOMException

I'm trying to use C3 to render a chart in my React project.
The problem
What I do is dynamically generate an id (UUID) and attach it to a div in my chart component. I then call some code after the component has rendered in componentDidMount. This is a common pattern, I have seen it in other projects.
At first, everything seemed fine. However, after repeatedly refreshing the page, sometimes the chart generation does not work. The error I get is:
DOMException: Failed to execute 'querySelector' on 'Document': '#a-really-long-id' is not a valid selector.
What I tried
I tried using setTimeout to delay when the chart was attached, but curiously I still got the same result, even after a 10 second delay. This leads me to believe that this is not a race condition, and caused by something else. Maybe C3 reads the DOM once and does not respond to changes? But that would not explain why it works sometimes...
Even trying to select the element by id from the Chrome developer console did not work.
Code
Here is my full component code:
// assets/js/index.jsx
import React from 'react';
import uuid from 'uuid/v4';
import c3 from 'c3';
class Chart extends React.Component {
constructor(props) {
super(props);
this.id = uuid();
this._update = this._update.bind(this);
}
_update() {
const data = this.props.data;
this.chart = c3.generate({
bindto: `#${this.id}`,
data: {
columns: [
['Male', 0],
['Female', 0],
['Brand', 0]
],
type: 'bar',
colors: {
Male: '#0066CC',
Female: '#FF6666',
Brand: '#808080'
},
groups: [
['Male', 'Female', 'Brand']
],
order: null
},
bar: {
width: {
ratio: 0.3
}
},
transition: {
duration: 500
},
tooltip: {
show: false
},
axis: {
x: { show: false },
y: { show: false },
},
size: { width: 220, height: 320 },
grid: {
x: { show: false }
},
legend: {
show: false
}
});
setTimeout(function() {
this.chart.load({
columns: [
['Male', data.male],
['Female', data.female],
['Brand', data.brand]
]
});
}, 500);
}
componentDidMount() {
this._update();
}
render() {
return (
<div id={this.id} className="chart"></div>
);
}
}
export default Chart;
This can be added as a comment, but since its big, adding it as an answer.
Are you using html4/ html5 semantics?
As per HTML4 (https://www.w3.org/TR/html401/types.html)
ID and NAME tokens must begin with a letter ([A-Za-z]) and may be
followed by any number of letters, digits ([0-9]), hyphens ("-"),
underscores ("_"), colons (":"), and periods (".").
As per HTML5 (https://www.w3.org/TR/html5/dom.html)
When specified on HTML elements, the id attribute value must be unique
amongst all the IDs in the element’s tree and must contain at least
one character. The value must not contain any space characters.
Your uuid might be generating a valid Id sometimes and sometimes it might not (not sure how uuid works)
If you are not using HTML5 semantics, you can simply add <!DOCTYPE html>
at the top of your html document and give a try.
Also,
You used settimeout in your logic and within that you used this.Chart
this, now will refer to settimeout rather than the class.
Can you try changing
setTimeout(function() {
this.chart.load({
columns: [
['Male', data.male],
['Female', data.female],
['Brand', data.brand]
]
});
}, 500);
to
setTimeout( () => {
this.chart.load({
columns: [
['Male', data.male],
['Female', data.female],
['Brand', data.brand]
]
});
}, 500);

cytoscape.js redundant edges

cytoscape.js to fails to render the graph if the graph has redundant edges/arcs. Why is this happening?
Example:
https://jsfiddle.net/smiccke/mq5t1rw9/4/
$(function() {
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
ready: function() {},
style: [{
selector: 'node',
css: {
'content': 'data(name)'
}
}, {
selector: 'edge',
css: {
'target-arrow-shape': 'triangle'
}
}],
elements: {
nodes: [{
data: {
id: 'j',
name: 'Jerry'
}
}, {
data: {
id: 'e',
name: 'Elaine'
}
}, {
data: {
id: 'k',
name: 'Kramer'
}
},
],
edges: [{
data: {
source: 'j',
target: 'e'
}
}, {
data: {
source: 'j',
target: 'k'
}
}
]
}
});
});
The graph works if you remove the two redundant edges from the end (j->e, j->e).
It seems like one redundant edge is ok, but two or more is a problem. Any clues why this is so?
As workaround, any nice short-cuts to remove redundant edges from the graph?
All the edges are there. You've rendered all parallel edges on top of one another, because that's how your edge style is specified.
Use appropriate style for the type of graph you're rendering. E.g., a multigraph should probably use haystack edges with a non-zero haystack radius or bundled bezier edges.
Refer to curve-style etc. in the docs: http://js.cytoscape.org/#style/edge-line
Edit: you mention that cytoscape.js fails to render the graph, but it renders fine for me. Are you truly not seeing any graph at all? If so, what browser are you using, and have you checked your code for errors?
Multiple edges between nodes default along the same path as maxkfranz said. You can set the 'curve-style': 'bezier' which will show all of the edges, or use 'haystack-radius': 1 to keep straight lines (play with values between 0 and 1).
I also noticed you have directed arrows turned on. These won't work with the default 'haystack' curve style, so I would suggest you use 'bezier' if you want to visualize directed edges.

Keep duplicates in array

I want to have an array of key:value pairs, but there might be duplicates.
Intention: Array of tasks, and each task has multiple operations. (I need the key/value for the operations, only that is required)
Right now the last item's value keeps overwriting the first key.
I currently have this, which solves my issue, but is there a better way to do this?
[
[
{
resize: [1200, 1200]
}, {
moveTo: "dest/nick"
}, {
rename: "{base}-12.{ext}"
}, {
toWeb: true
}, {
rename: "{base}.{ext}"
}
], [
{
resize: [1000, 1000]
}, {
rename: "{base}-10.{ext}"
}
]
]
The resize, moveTo and rename are only pseudo options, many more things. And I need duplicates.
edit
This is a configuration. (Input) kinda like json, I think. It has to be parsed
EDIT
The above code works I simply wanted a better way to do this, so I have asked it over at CodeReview
perhaps it is easier to think from reverse side, first how you would use it, then how you should define the data structure.
e.g. task[i].operation1; task[i].operation2
then it should be:
task = [
{ resize: [1200, 1200], moveTo: "dest/nick, ..... },
{ resize: [1000, 1000], rename: "{base}-10.{ext}", ..... }
]

Creating a custom library in javascript for a table

I'm trying to build a custom library for my table, I want to add an option where for each column (th) I may be able to defined their width depends to what I declared. For example I only need to define the width of the first and second column (th) and I have 8 columns, there rest of the column should have width.
My sample snippets inside my table prototype:
init: function (el, options) {
column: {
width: [20, 200, 500]
}
}
I am not really sure how to, since I'm starting to learn javascript. For now I'm just up to adding the width, sooner or later I'll be adding more options inside the column, like color etc.
Additional information: I want pure JavaScript without using other library (jQuery) to my library.
Model-wise you probably want something like:
{
columns: [ {
label: "Foo",
width: 50 // px
}, {
label: "Bar",
width: 100 // px
}, {
label: "Baz",
width: "*"
} ]
}
instead of
{
column_widths: [ 50, 100, "*" ]
column_labels: [ "Foo", "Bar", "Baz" ]
}
The "*" would translate to a column with no defined width so the browser will decide how wide it is. Whether that is desirable or not is up to you.

Javascript chart with multiple "chart areas"

Can anyone suggest a Javascript chart library that could produce such chart: Refer this Image
The emphasis here is on two separate areas: history and schedule. Each of them should have a different title and background color. Basically, it would be great if each area is configurable separately.
I tried Google Charts but did not see how to implement it in a clean way. I could create two charts with a specific layout, but I would prefer a more dynamic and correct way of doing that.
If you're looking for a charting library to accomplish this, ZingChart would do the trick. By setting "layout" in the graphset object to "x2" and creating two separate chart objects, your charts are set up side-by-side but can still be manipulated individually. I've included a demo below for reference. Run it to see the chart.
You can download the entire library for free on the site. If you have any questions, I'm on the team and happy to help! You can reach us at support#zingchart.com.
var myChart = {
"layout":"x2",
"background-color":"#eee",
"border-color":"#000",
"border-width":2,
"graphset":[
{
"type":"bar",
"background-color":"#eee",
"width":"60%",
"x":0,
"y":0,
"title":{
"text":"Chart 1",
"text-align":"left",
"font-color":"black",
"background-color":"#ddd"
},
"scale-x":{
"values":["2007","2008","2009","2010","2011","2012","2013","2014"],
"label":{
"text":"History",
"offset-x":-125,
"padding-top":10
},
"tick":{
"visible":false
},
"guide":{
"visible":false
}
},
"scale-y":{
"values":"0:12:2",
"guide":{
"line-style":"solid"
}
},
"plot":{
"stacked":true
},
"plotarea":{
"margin-right":0,
"background-color":"#ddd"
},
"legend":{
"shared":true,
"visible":false
},
"series":[
{
"values":[3,5,5,5,8,6,4,3],
"background-color":"#018BD3"
},
{
"values":[null,null,null,null,3,null,null,null],
"background-color":"#F27D30"
},
{
"values":[],
"background-color":"#F2D134"
},
{
"values":[null,null,null,null,null,2,null,2],
"background-color":"#14AE13"
}
]
},
{
"type":"bar",
"background-color":"#eee",
"width":"40%",
"x":"60%",
"y":0,
"title":{
"text":"Chart 2",
"text-align":"left",
"font-color":"black",
"background-color":"#ccc"
},
"scale-x":{
"values":["2015","2016","2017"],
"tick":{
"visible":false
},
"guide":{
"visible":false
},
"label":{
"text":"Schedule",
"offset-x":-25,
"padding-top":10
}
},
"scale-y":{
"values":"0:12:2",
"line-color":"#777",
"tick":{
"visible":false
},
"item":{
"visible":false
},
"guide":{
"line-style":"solid"
}
},
"plot":{
"stacked":true
},
"plotarea":{
"margin-left":0,
"margin-right":"50%",
"background-color":"#ccc"
},
"legend":{
"shared":true
},
"series":[
{
"values":[7,1,0],
"background-color":"#018BD3"
},
{
"values":[],
"background-color":"#F27D30"
},
{
"values":[3,6,1],
"background-color":"#F2D134"
},
{
"values":[1,null,null],
"background-color":"#14AE13"
}
]
}
]
};
zingchart.render({
id : "myChart",
height : "300px",
width : "100%",
data : myChart
});
<script src="http://www.zingchart.com/playground/lib/zingchart/zingchart-html5-min.js"></script>
<div id="myChart"></div>
You can try d3Js - examples library.
The possible solution is you have to define Two graph separately with using <div> tag.
Give each of them separate CSS values (for colors and your specific needs), And then define both <div> under single division.
First try to edit JsFiddle
You can try LightningChart JS library. We have an extensive dashboard API which allows you to group multiple independent and customizable charts into a layout which can then also be resized on the fly.
You should take a look at our interactive examples for this specific use case Dashboard Example.
Full disclosure: I am a developer for LightningChart, I think you may find this very useful.

Categories