Cytoscape layout to use node attributes as coordinates? - cytoscape

Is there a way to use x,y coordinates stored as attributes of each node to layout a graph using the coordinates that were calculated by another program?
And if not, would it be possible to implement this somehow - how does one get started on this?
Is there a standard way how to provide the node positions to the cytoscape.js web viewer somehow?
Background: it is trivial to use Python networkx to calculate some layouts which are not supported in Cytoscape, and it would also be trivial to store the coordinates as node attributes. All that would then be need is some way for Cytoscape to use those coordinates to find node positions instead of using a layout algorithm.

This is a quite easy thing to do. Many examples on use this functionlity in the demos, as you can see here:
1: FCose Demo
2: Cose Blicent Demo
3: d3-force Demo
4: Euler Compound Demo
5: Spread Demo
As you can see, there are an abundance of examples for this in the demos, but also in the docs. You can see one here and here:
// can use reference to eles later
var eles = cy.add([
{ group: 'nodes', data: { id: 'n0' }, position: { x: 100, y: 100 } },
{ group: 'nodes', data: { id: 'n1' }, position: { x: 200, y: 200 } },
{ group: 'edges', data: { id: 'e0', source: 'n0', target: 'n1' } }
]);
The json used in the .add() function can be created in your js application or directly in Python and added to the graph as some of the examples do.
In general, you should take some time and skim through through the docs. The ability to position nodes via x and y is quite basic and is one of the first pages in the docs.
If you don't understand the description in the docs and the examples I provided, please edit your question and add your current code as a Minimal, Reproducible Example, where you can show your efforts to implement the positioning.
Edit:
As #maxkfranz pointed out, the preset layout plays a big role here. The documentation states this in the Initialisation Chapter:
If you want to specify your node positions yourself in your elements JSON, you can use the preset layout — by default it does not set any positions, leaving your nodes in their current positions (i.e. specified in options.elements at initialisation time).`

I am new to using Cytoscape so things that are "easy" are not so easy for me. I often don't even know the right way to ask a question. Everyone has things that are hard and things that are easy, and step by step we expand our knowledge so what is hard today may be easy tomorrow.
Anyway, here is something that may be a part of the solution you are looking for:
In the Cytoscape desktop application, you can create a "Style" that maps a node attribute to "X Location" and another node attribute to "Y Location".

Related

Vaadin 14 FlagItems not aligned correctly on ListSeries

I've got a problem regarding the FlagItem in Vaadin 14.
I'm trying to set a FlagItem for a specific point in a ListSeries, I'm doing this the following way:
PlotOptionsFlags plotOptionsFlags = new PlotOptionsFlags();
plotOptionsFlags.setOnSeries(wageEntry.getEmployeeCode());
plotOptionsFlags.setShape(FlagShape.SQUAREPIN);
plotOptionsFlags.getTooltip().setPointFormat("Wage: {point.y}");
plotOptionsFlags.getTooltip().setHeaderFormat("");
plotOptionsFlags.setShowInLegend(false);
DataSeries flagsSeries = new DataSeries();
flagsSeries.setName(wageEntry.getEmployeeCode().concat(" Current Wage"));
flagsSeries.setPlotOptions(plotOptionsFlags);
for (WageEntry wage : employeeWageEntries) {
if (wage.getWageYear() == LocalDate.now().getYear()) {
flagsSeries.add(new FlagItem(wage.getAge() - 22, wage.getEmployeeCode().concat(" - ").concat(String.valueOf(wage.getWageAmount()))));
}
}
comparisonChartConfiguration.addSeries(flagsSeries);
As you can see, I set the x value relative to the age of an entry, and the text. More over the FlagItem is only created when a certain condition is met. (I used the Vaadin Chart Demo as reference: https://demo.vaadin.com/charts/Flags)
The problem now is, that when the chart is being built, the FlagItem appear on the x axis instead as you can see here:
I really don't understand why this happens.
Maybe it's useful to know, that on the chart three RangeSeries and multiple ListSeries are being drawn.
Thanks for the help!
So I've found out where the problem was. It was something that wasn't added to the code above, so please have mercy.
The issues lied withing the fact that I didn't add the ListSeries to the comparisonChartConfiguration before creating the flagsSeries.
In short, you need to add the Series you want to append flags on to the ChartConfiguration before you can attach the flagsSeries onto another.

Printing an image to a dye based application

I am learning about fluid dynamics (and Haxe) and have come across this awesome project and thought I would try to extend to it to help me learn. A demo of the original project in action can be seen here.
So far, I have created a side menu of items containing different shapes. When the user clicks on one of the shapes, then, clicks onto the canvas, the image selected should be imprinted onto the dye. The user will then move the mouse and explore the art etc.
To try and achieve this I did the following:
import js.html.webgl.RenderingContext;
function imageSelection(): Void{
document.querySelector('.myscrollbar1').addEventListener('click', function() {
// twilight image clicked
closeNav();
reset();
var image:js.html.ImageElement = cast document.querySelector('img[src="images/twilight.jpg"]');
gl.current_context.texSubImage2D(cast fluid.dyeRenderTarget.writeToTexture, 0, Math.round(mouse.x), Math.round(mouse.y), RenderingContext.RGB, RenderingContext.UNSIGNED_BYTE, image);
TWILIGHT = true;
});
After this call, inside the update function, I have the following:
override function update( dt:Float ){
time = haxe.Timer.stamp() - initTime;
performanceMonitor.recordFrameTime(dt);
//Smaller number creates a bigger ripple, was 0.016
dt = 0.090;//#!
//Physics
//interaction
updateDyeShader.isMouseDown.set(isMouseDown && lastMousePointKnown);
mouseForceShader.isMouseDown.set(isMouseDown && lastMousePointKnown);
//step physics
fluid.step(dt);
particles.flowVelocityField = fluid.velocityRenderTarget.readFromTexture;
if(renderParticlesEnabled){
particles.step(dt);
}
//Below handles the cycling of colours once the mouse is moved and then the image should be disrupted into the set dye colours.
}
However, although the project builds, I can't seem to get the image imprinted onto the canvas. I have checked the console log and I can see the following error:
WebGL: INVALID_ENUM: texSubImage2D: invalid texture target
Is it safe to assume that my cast for the first param is not allowed?
I have read that the texture target is the first parameter and INVALID_ENUM in particular means that one of the gl.XXX parameters are just flat out wrong for that particular function.
Looking through to the file writeToTexture is declared as so: public var writeToTexture (default, null):GLTexture;. WriteToTexture is a wrapper around a regular webgl handle.
I am using Haxe version 3.2.1 and using Snow to build the project. WriteToTexture is defined inside HaxeToolkit\haxe\lib\gltoolbox\git\gltoolbox\render
writeToTexture in gltoolbox is a GLTexture. With snow and snow_web, this is defined in snow.modules.opengl.GL as:
typedef GLTexture = js.html.webgl.Texture;
So we're simply dealing with a js.html.webgl.Texture here, or WebGLTexture in native JS.
Which means that yes, this is definitely not a valid value for texSubImage2D()'s target, which is specified to take one of the gl.TEXTURE_* constants.
A GLenum specifying the binding point (target) of the active texture.
From this description it's obvious that the parameter isn't actually for the texture itself - it merely gives some info on how the active texture should be used.
The question then becomes how the "active" texture can be set. bindTexture() can be used for this.

How to dynamically set binding type's "formatOptions" and "constraints" in XML with binding?

I have a list of elements (OData set) and use a binding to show this list.
One field is for a quantity value and this value could sometimes need some decimal places.
The requirement is: only show that amount of decimal numbers that is also available in the OData service.
Annotation techniques can't be used.
I 'hacked' something that is misusing a formatter to update the type of a binding. But this is 'a hack' and it is not possible to convert it to XML views. (The reason is a different handling of the scope the formatter will be called).
So I am searching for a working solution for XML views.
The following code would not work but shows the issue:
new sap.m.Input({ // looking for an XML solution with bindings
value: {
path: "Quantity",
type: new sap.ui.model.type.Float({
// formatOptions
maxFractionDigits: "{QuantityDecimals}",
// ...
}, {
// constraints
minimum: 0
}),
// ...
}
});
The maxFractionDigits : "{QuantityDecimals}" should be "dynamic" and not a constant value.
Setting formatOptions and constraints dynamically in XML (via bindings or a declared function) is unfortunately not (yet) supported. But IMHO this is a valid enhancement request that app developers would greatly benefit from, since it encourages declarative programming.
I already asked for the same feature some years ago but in a comment at https://github.com/SAP/openui5/issues/2449#issuecomment-474304965 (See my answer to Frank's question "If XMLViews would allow a way to specify the dynamic constraints as well (e.g. enhanced syntax), would that fix the problem?").
Please create a new issue via https://github.com/SAP/openui5/issues/new with a clear description of what kind of problems the feature would resolve and possibly other use cases (You can add a link to my comment). I'll add my 👍 to your GitHub issue, and hopefully others too.
I'll update this answer as soon as the feature is available.
Get your dynamic number from your model and store it in a JS variable.
var nQuantityDecimals = this.getModel().getProperty("/QuantityDecimals");
new sap.m.Input({
value : {
path : "Quantity",
type : new sap.ui.model.type.Float({
maxFractionDigits : nQuantityDecimals,
source : {
groupingSeparator: ",",
decimalSeparator: ".",
groupingEnabled: false
}
}, {
minimum:0
})
}
}),

Possible to make a composite symbol?

When editing a vertex I would like to substitute the vertex symbol with SimpleMarkerSymbol and a TextSymbol but that appears to be impossible. Any suggestions on how I could do this? I want the appearance of dragging something like this (text + circle):
After taking some time to look at the API I've come to the conclusion it is impossible. Here is my workaround:
editor.on("vertex-move", args => {
let map = this.options.map;
let g = <Graphic>args.vertexinfo.graphic;
let startPoint = <Point>g.geometry;
let tx = args.transform;
let endPoint = map.toMap(map.toScreen(startPoint).offset(tx.dx, tx.dy));
// draw a 'cursor' as a hack to render text over the active vertex
if (!cursor) {
cursor = new Graphic(endPoint, new TextSymbol({text: "foo"}));
this.layer.add(cursor);
} else {
cursor.setGeometry(endPoint);
cursor.draw();
}
})
You could use a TextSymbol to create a point with font type having numbers inside the circle. Here is one place where you can find such font. http://www.fontspace.com/the-fontsite/combinumerals
Wont be exactly as shown in the image but close enough. Also some limitation it wont work with IE9 or lower (this is as per esri documentation, as I am using halo to get the white border).
Here is the working Jsbin : http://jsbin.com/hayirebiga/edit?html,output use point of multipoint
PS: I have converted the ttf to otf and then added the font as base64, which is optional. I did it as I could not add the ttf or otf to jsbin.
Well, Achieve this seems impossible so far however ArcGIS JS API provides a new Application/platform where you can generate single symbol online for your applications.
We can simply create all kind of symbols(Provide by ESRI) online and it gives you on the fly code which you just need to paste in your application.
This will help us to try different type of suitable symbols for the applications.
Application URL: https://developers.arcgis.com/javascript/3/samples/playground/index.html
Hoping this will help you :)

Cesium path onto terrain: line connecting 2 points goes under the terrain

I have a path moving over time.
I use Cesium.sampleTerrain to get positions elevation and drape them on the terrain.
The problem is that, even if all points are on the terrain, the line connecting 2 points sometimes goes under the terrain.
How can I do to drape also connecting lines on the terrain?
Here is my code:
var promise = Cesium.sampleTerrain(terrainProvider, 14, positions);
Cesium.when(promise, function(updatedPositions) {
var cartesianPositions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(updatedPositions);
var sample = new Cesium.SampledPositionProperty();
sample.setInterpolationOptions({
interpolationDegree : 3,
interpolationAlgorithm : Cesium.HermitePolynomialApproximation
});
$(cartesianPositions).each(function(index, cartPosition) {
var time = Cesium.JulianDate.addSeconds(start, index*10, new Cesium.JulianDate());
sample.addSample(time, cartPosition);
})
var target = viewer.entities.add({
position: sample,
path: {
resolution: 60,
material:Cesium.Color.BLUE,
width: 4,
trailTime: 422*10,
leadTime: 0
}
});
});
So like Matthew says; Cesium doesn't currently support a 'polyline' type entity with draping over terrain.
If you find that the Entity API isn't giving you what you need, it might be worth digging into the lower-level Primitives API to gain finer control - more specifically the GroundPrimitive geometry.
Among others; GroundPrimitives currently support the CorridorGeometry.
I have no experience with temporal data plotting within Cesium, but I would suggest you consider this approach rather than the async promise approach, which (IMO) seems like more of a hack born from the absence of a GroundPrimitive-type solution at the time.
Here's a crude example of a GroundPrimitive in action (note we don't need any z values):
var viewer = new Cesium.Viewer('cesiumContainer');
var corridorInstance = new Cesium.GeometryInstance({
geometry : new Cesium.CorridorGeometry({
vertexFormat : Cesium.VertexFormat.POSITION_ONLY,
positions : Cesium.Cartesian3.fromDegreesArray([
-122.26, 46.15,
-122.12, 46.26,
]),
width : 100
}),
id : 'myCorridor',
attributes : {
color : new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
}
});
var corridorPrimitive = new Cesium.GroundPrimitive({
geometryInstance : corridorInstance
});
viewer.scene.primitives.add(corridorPrimitive);
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(-122.19, 46.20, 10000.0)
});
Which will give you this:
Cesium does not currently support draping lines on terrain, but it is on our road map and really important to us. This is actually an extremely complicated problem to handle correctly in all cases (and is even more complicated because of the limitations of WebGL). It will require a lot of research and experimentation and there's no hard timeline for when it will be finished. We should have a version of it for static lines by spring as part of our 3D Tiles work, but dynamic lines are probably further out.
If you're interested in following development of this feature, keep your eye on issue #2172 in our GitHub repository. We'll also make announcements on our blog/twitter/forum when this feature is part of an official release.

Resources