How do I get graphviz to generate fixed sized subgraphs? - size

I've been struggling with this for a while and cannot seem to find a straight answer. I'm working with compound subgraphs in graphviz and cannot seem to find the right combination of settings to force two subgraphs to align with each other.
Enclosed is a simple example to show the problem...
digraph g {
compound=true;
subgraph cluster_top {
graph [color=black, label="Top", rank=min];
nodeA; nodeB; nodeC
cluster_top_DUMMY [shape=point style=invis]
}
subgraph cluster_service {
graph [color=black, label="Bottom", rank=min];
node1; node2; node3; node4; node5; extra_long_node
cluster_bottom_DUMMY [shape=point style=invis]
}
cluster_top_DUMMY -> cluster_bottom_DUMMY [ style=invis ]
}
This generates output with the Bottom subgraph significantly wider than the Top subgraph.
What I really want is for to ensure that both Top and Bottom are always exactly the same width. In addition, if there are too many nodes to fit into the available width, it would generate additional rows of nodes.

A possible (bad but working) solution would be to use invisible nodes and set width.
Consider the following:
digraph g {
compound=true;
subgraph cluster_top {
graph [color=black, label="Top", rank=min];
nodeAI0 [style=invisible]
nodeAI1 [style=invisible]
nodeAI2 [style=invisible,fixedsize=true,width=1.65]
nodeA; nodeB; nodeC
cluster_top_DUMMY [shape=point style=invis]
}
subgraph cluster_service {
graph [color=black, label="Bottom", rank=min];
node1; node2; node3; node4; node5; extra_long_node
cluster_bottom_DUMMY [shape=point style=invis]
}
cluster_top_DUMMY -> cluster_bottom_DUMMY [ style=invis ]
}
The invisible nodes (NodeAI0-NodeAI2) take the space. fixedsize=true,width=1.65 makes the last one take exactly 1.65 inches.
Another, better solution would be to also set the relevant longer node specifically (to avoid having to look for the correct value) by adding something like:
node [fixedsize=true,width=0.75]
after the compound=true portion.

Related

How does faceeffect decide where to attach the 3dmesh? e.g attach the axis to the nose

Looking into below Mediapipe's faceeefect module's graph definition
node_options: {
[type.googleapis.com/mediapipe.SwitchContainerOptions] {
contained_node: {
calculator: "FaceGeometryEffectRendererCalculator"
node_options: {
[type.googleapis.com/mediapipe.FaceGeometryEffectRendererCalculatorOptions] {
effect_texture_path: "mediapipe/graphs/face_effect/data/axis.pngblob"
effect_mesh_3d_path: "mediapipe/graphs/face_effect/data/axis.binarypb"
}
}
}
I further checked the calculator code of FaceGeometryEffectRendererCalculator, I couldn't pinpoint the code where it determines the exact location the renderer render the axis. Maybe I don't understand the OpenGL well which leads to the misunderstanding.
Can someone help shed some lights where should I look for?
Thanks!
By digging into the document and paper I get to understand that the estimated face geometry is aligned with the canonical face model. You can refer the pager https://arxiv.org/pdf/1907.06724.pdf and the explanation here

Cytoscape disappearing edges with bezier curves and nodes moving/longer labels in nodes

I am using cytoscape with bezier curves but edges are disappearing when having a node with longer label or just moving source node next to target node.
Video: https://www.screencast.com/t/N2f5eZ5M7
Runnable sample: https://stackblitz.com/edit/web-platform-vpl72r?file=index.html
I have already seen "Edge xxxxx has invalid endpoints and so it is impossible to draw" warning and searched corresponding threads but couldn't find a solution.
Does anyone know how to handle that ?
I see some warnings on the console
The style value of label is deprecated for width
The style value of label is deprecated for height
After I deleted 'width': 'label', 'height':'label', I no longer observe such problem.
--- Update 1.1 ---
but I'd like to have node's dimensions based on label's dimensions.
To do this I think you should write a function style. See the below example. In the example, you can see that we are setting the size of the nodes dynamically based on their name length. I assumed name is a string that stores labels.
cy.style().selector('node').style({
'width': (x) => { return x.data('name').length + 'px;' }
'height': (x) => { return x.data('name').length + 'px;' }
}).update();

visjs network arrow customization

I need to show "?" instead of the standard arrows types in my visjs network.
I followed this solution:
How to change arrows in vis.js to chicken feet or cardinality
However I also need to hide and show nodes based on a property on it. Once the nodes are hidden and shown again, the "?" on edges is lost and the edges default to the standard arrow heads.
Fiddle: https://jsfiddle.net/gu2kwze0/51/
network.getEdgeById('1').drawArrows = function drawArrows(ctx, arrowData) {
ctx.font = "20px OpenSans";
if (this.options.arrows.to.enabled === true) {
//'to' side suspect
ctx.fillText('?', arrowData.to.point.x, arrowData.to.point.y);
}
if (this.options.arrows.from.enabled === true) {
//only 'from' side suspect
ctx.fillText(' ? ', arrowData.from.point.x, arrowData.from.point.y);
}
}
Click in the network to hide & then show the edges.
What could be wrong?

How do I prevent touches from hitting hidden content in SKCropNode?

I'm making pretty heavy use of SKCropNode in my game both for stylistic uses and also in one case where I've built my own SpriteKit version of UIScrollView. I've noticed that when I get a touch event or when a gesture recognizer fires at a certain point, SKScene.nodeAtPoint(...) is still hitting nodes that are hidden at the touch point from the crop node.
How do I prevent SKScene.nodeAtPoint(...) from hitting cropped content, and instead return the next visible node beneath it?
You can't. Everything is based on the frame of the content, and with crop nodes, it is huge. The only thing you can do is check the point of touch, use nodesAtPoint to get all nodes, then enumerate one by one, checking whether or not the touch point is touching a visible pixel by either checking the pixel data, or having a CGPath outlining of your sprite and checking if you are inside that.
I managed to work my way around this one, but it isn't pretty and it doesn't work in every scenario.
The idea is, when a touch is recorded, I iterate over all nodes at that point. If any of those nodes are (or are children of) SKCropNodes, I check the frame of the mask on the crop node. If the touch lies outside the mask, we know the node is not visible at that point and we can assume the touch didn't hit it.
The issue with this method is that I don't do any evaluation of transparency within the crop mask - I just assume it's a rectangle. If the mask is an abnormal shape, I may give false positives on node touches.
extension SKScene {
// Get the node at a given point, but ignore those that are hidden due to SKCropNodes.
func getVisibleNodeAtPoint(point: CGPoint) -> SKNode? {
var testedNodes = Set<SKNode>()
// Iterate over all the nodes hit by this click.
for touchedNode in self.nodesAtPoint(point) {
// If we've already checked this node, skip it. This happens because nodesAtPoint
// returns both leaf and ancestor nodes, and we test the ancestor nodes while
// testing leaf nodes.
if testedNodes.contains(touchedNode) {
continue
}
var stillVisible = true
// Walk the ancestry chain of the target node starting with the touched
// node itself.
var currentNode: SKNode = touchedNode
while true {
testedNodes.insert(currentNode)
if let currentCropNode = currentNode as? SKCropNode {
if let currentCropNodeMask = currentCropNode.maskNode {
let pointNormalizedToCurrentNode = self.convertPoint(point, toNode: currentCropNode)
let currentCropNodeMaskFrame = currentCropNodeMask.frame
// Check if the touch is inside the crop node's mask. If not, we
// know we've touched a hidden point.
if
pointNormalizedToCurrentNode.x < 0 || pointNormalizedToCurrentNode.x > currentCropNodeMaskFrame.size.width ||
pointNormalizedToCurrentNode.y < 0 || pointNormalizedToCurrentNode.y > currentCropNodeMaskFrame.size.height
{
stillVisible = false
break
}
}
}
// Move to next parent.
if let parent = currentNode.parent {
currentNode = parent
} else {
break
}
}
if !stillVisible {
continue
}
// We made it through the ancestry nodes. This node must be visible.
return touchedNode
}
// No visible nodes found at this point.
return nil
}
}

Circle layout with custom center coordinates

I'm building a dynamic graph with cytoscape.js over a world map generated with jVectorMap.
Starting with coordinates in LAT / LON format from json data, I can convert them in point.x / point.y over the generated map with:
var nodePoint = theMap.latLngToPoint(node.data.lat, node.data.lon)
and then I can add the new node in the graph with:
cy.add({
group: "nodes",
position: { x: nodePoint.x, y: nodePoint.y },
style: {
'background-color': node.color
},
data: {
id: node.id,
name: node.label,
customData: node.data,
}
})
This part works, but when json returns multiple nodes with the same coordinates, I would like to spread these nodes around the point with the common LAT / LON information.
I'm able to identify these nodes and apply a dedicated layout to them, but the resulting layount is located in the center of the screen / div of graph.
What I want to know is if there is a simple way to apply a Circle Layout with specific center point.
(I would like to avoid implementing the solution that I'm evaluating... i.e to build a bounding box around the center point and see what happens, (with the bounding box size that grows along with node number in the same point))
In the Wine and cheese example included in the documentation they use the bounding box to force a concentric layout around a selected node ( http://js.cytoscape.org/demos/cde4db55e581d10405f5/ ).
While you indicate you would like to avoid this solution it seems a straightforward solution. The implementation in the example is rather elegant.