Repository: cytoscape/cytoscape.js (2025-07-15T16:17:50Z)

Issue:
Single element cose layout has no display
**Before you post**

A request for help or a request for a how-to should be directed to [Phind]([url](https://www.phind.com/search?c=I%27m%20using%20the%20Cytoscape.js%20graph%20theory%20JS%20library.&q=How%20do%20I%20create%20a%20graph%20in%20my%20HTML%20page)).

If your issue pertains to an extension, your issue should be filed in that extension's repository -- not here.



**Environment info**

- Cytoscape.js version : 3.30.0
- Browser/Node.js & version : Chrome 131.0.6778.264



**Current (buggy) behaviour**

_What does the bug do?_

When cose layout, if there is only one element, nothing will be displayed.


**Desired behaviour**

_What do you expect Cytoscape.js to do instead?_

I want to show.

**Minimum steps to reproduce**

_What do you need to do to reproduce the issue?_

_Fork/clone this JSBin demo and reproduce your issue so that your issue can be addressed quickly and effectively:_

1. Go to our base JSBin: http://jsbin.com/fiqugiq
2. Click the 'Edit in JSBin' button in the top-right corner.
3. Click File > Clone to make your own copy of the demo (with its own unique URL) that you can edit.
4. Click the yellow 'Login or Register' button at the top-right corner so that your JSBin persists longer-term.
5. Log in with your GitHub account.
6. Edit the JSBin to reproduce your issue.
7. When you're finished editing, click 'File > Save snapshot` (command + s) to save your edits.
8. Post the link to your JSBin here.



**For reviewers**

_Reviewers should ensure that the following tasks are carried out for incorporated issues:_

- [x] Ensure that the reporter has included a reproducible demo.  They can easily fork this JSBin demo: http://jsbin.com/fiqugiq
- [x] The issue has been associated with a corresponding [milestone](https://github.com/cytoscape/cytoscape.js/milestones).
- [ ] The commits have been incorporated into the corresponding branches.  Bug-fix patches go on
    - [ ] `master` and
    - [ ] `unstable`.
- [x] The issue has been labelled as a [`bug`](https://github.com/cytoscape/cytoscape.js/labels/bug), if necessary.




Discussion:
Thank you for the report.

I haven't been able to reproduce the issue, though.
I've tried with the network containing only one node. Also, all edges must be commented out to avoid a Cytoscape.js error that would prevent the network from being rendered:

<img width="1017" alt="Image" src="https://github.com/user-attachments/assets/2e632570-5beb-4fb5-a51b-4f34d0ca48fb" />
<br /><br />

Could you please confirm if this matches your reproduction steps? 
Thanks!
**Apologies for the delayed response.**  
The abnormal occurs only when a bounding box is explicitly configured. As shown below:

**Template (html):**
```html
<div #divCy class="cytoscape-content"></div
```

**Component (TypeScript):**
```typescript
@ViewChild('divCy', static: true }) private divCy!: ElementRef<HTMLDivElement>;

const boundingBox DOMRect = this.divCy.nativeElement.getBoundingClientRect();
this.config.layout = {
  name:cose',
  boundingBox: {
    x1: 0,
    y1 0,
    w: boundingBox.width,
    h: boundingBox.height
  }
};
```

@10196 Could you replicate this in the jsfiddle demo, perhaps with a container that has the same reported dimensions as your `boundingBox`?
@maxkfranz  https://jsfiddle.net/dphwc5qv/8/
You can remove the boundingBox to show the icon
@10196, thanks for the demo.  In the meantime, you could conditionally use the `grid` layout when you detect `numNodes<=1`
@maxkfranz 
Yes, I can use `grid` to circumvent this problem. 
If possible, I would like `cose` to support this scenario, or note this problem in the documentation. If other `layout` also have this problem, deal with them in the same way.
@10196 Try the patch in PR https://github.com/cytoscape/cytoscape.js/pull/3396 and let us know if it works for you



Patch:
diff --git a/src/extensions/layout/cose.mjs b/src/extensions/layout/cose.mjs
index 10b4af55b..a97af9bfb 100644
--- a/src/extensions/layout/cose.mjs
+++ b/src/extensions/layout/cose.mjs
@@ -644,8 +644,9 @@ var getScaleInBoundsFn = function( layoutInfo, options, nodes ){
     var lnode = layoutInfo.layoutNodes[ layoutInfo.idToIndex[ ele.data( 'id' ) ] ];
 
     if( options.boundingBox ){ // then add extra bounding box constraint
-      var pctX = (lnode.positionX - coseBB.x1) / coseBB.w;
-      var pctY = (lnode.positionY - coseBB.y1) / coseBB.h;
+      // Handle single node case where coseBB.w or coseBB.h is 0
+      var pctX = coseBB.w === 0 ? 0.5 : (lnode.positionX - coseBB.x1) / coseBB.w;
+      var pctY = coseBB.h === 0 ? 0.5 : (lnode.positionY - coseBB.y1) / coseBB.h;
 
       return {
         x: bb.x1 + pctX * bb.w,


Test patch:
diff --git a/playwright-tests/renderer.spec.js b/playwright-tests/renderer.spec.js
index e4c101e80..89f40e83a 100644
--- a/playwright-tests/renderer.spec.js
+++ b/playwright-tests/renderer.spec.js
@@ -568,4 +568,43 @@ test.describe('Renderer', () => {
 
   }); // Rounded edges
 
+  test.describe('with layout', () => {
+
+    test('single node cose layout with bounding box', async ({ page }) => {
+      const pos = await page.evaluate(async () => {
+        const cy = window.cy;
+
+        // remove all eles
+        cy.elements().remove();
+
+        // add one node
+        let node = cy.add({ data: { id: 'a' } }); 
+
+        // run layout
+        let layout = cy.layout({
+          name: 'cose',
+          boundingBox: {
+            x1: 0,
+            y1: 0,
+            x2: 100,
+            y2: 100
+          },
+        });
+
+        let layoutstop = layout.promiseOn('layoutstop');
+
+        layout.run();
+
+        await layoutstop;
+
+        return node.position();
+      });
+      
+      expect(pos.x).not.toBeNaN();
+      expect(pos.y).not.toBeNaN();
+
+    }); // single node cose layout
+
+  }); // with layout
+
 }); // renderer
\ No newline at end of file