Skip to content

Conversation

@schochastics
Copy link
Contributor

Trying to tackle #219.
The overarching issue is that if the layout is saved as a graph attribute (g$layout), independent on how it is done, there is no checks implemented if the layout matrix can actually
serve as a layout (that is, if it has the correct number of rows).
This leads to weird behaviour of the plot function.

This PR could be the starting point for a refactoring. Currently, it only adds a warning if the layout does not match the graph. @szhorvat could this be a good start?

devtools::load_all("~/git/R_packages/rigraph/")
#> ℹ Loading igraph
g <- make_ring(10)
g$layout <- layout_in_circle(g)
plot(induced_subgraph(g,c(1:9)))
#> Warning: The layout has 10 rows, but the graph has 9 vertices. Unintended results may
#> occur.

g <- make_full_graph(10)
g$layout <- layout_in_circle(g)[1:5,]
plot(g)
#> Warning: The layout has 5 rows, but the graph has 10 vertices. Unintended results may
#> occur.

g$layout <- rbind(layout_in_circle(g), cbind(runif(5),runif(5)))
plot(g)
#> Warning: The layout has 15 rows, but the graph has 10 vertices. Unintended results may
#> occur.

Created on 2025-06-24 with reprex v2.1.1

@szhorvat
Copy link
Member

I think a complete fix is only possible in the C core. We need support for attributes with vector values. I proposed this here for 1.0:

igraph/igraph#2744

But realistically, @ntamas and I just don't have the capacity to get this done for the 1.0 release, which is due in September.

My suggestion is to not put too much effort into this on the R side until it can be fixed in the C core. Perhaps discourage using $layout and suggest $x, $y instead ...

@ntamas Are there any hooks in the attribute handler that would allow updating such attributes upon vertex deletion/addition? I don't think there are any. Note that $layout is a graph attribute, which is the problem here.

@schochastics
Copy link
Contributor Author

Thanks. I will augment the warning to suggest using x and y and that should be good enough for now

@ntamas
Copy link
Member

ntamas commented Jun 24, 2025

Are there any hooks in the attribute handler that would allow updating such attributes upon vertex deletion/addition?

No, not until we implement some kind of a generic event emitter / listener system that would allow third-party code to hook into anything that happens with a graph.

@krlmlr
Copy link
Contributor

krlmlr commented Jun 26, 2025

An error would be better here. We discussed before that this should be a vertex attribute, AFAIR this isn't something that the C core currently supports.

@krlmlr
Copy link
Contributor

krlmlr commented Jun 26, 2025

The R core could support it, though, with #1894. What would it take to make the following code produce the right results?

library(igraph, warn.conflicts = FALSE)

g <- make_full_graph(10)
V(g)$layout <- layout_in_circle(g)
plot(g)

Created on 2025-06-26 with reprex v2.1.1

@schochastics schochastics added the plotting 💹 Issues related to plotting label Jun 27, 2025
@schochastics
Copy link
Contributor Author

Cant remember all discussions here: Should I turn the warning into an error message and then merge?

@krlmlr
Copy link
Contributor

krlmlr commented Jul 5, 2025

My question in #1880 (comment) is still relevant.

@schochastics
Copy link
Contributor Author

I'll investigate but I think this would be a big change.

  1. Matrix attributes are not supported for vertices and 2) The plot code assumes layout either to be a matrix graph attribute or x and y vertex attributes

@krlmlr
Copy link
Contributor

krlmlr commented Jul 5, 2025 via email

@krlmlr
Copy link
Contributor

krlmlr commented Jul 5, 2025

Specifically, this works with #1894:

library(igraph, warn.conflicts = FALSE)

g <- make_full_graph(10)
V(g)$layout <- layout_in_circle(g)
V(g)$layout
#>            [,1]          [,2]
#>  [1,]  1.000000  0.000000e+00
#>  [2,]  0.809017  5.877853e-01
#>  [3,]  0.309017  9.510565e-01
#>  [4,] -0.309017  9.510565e-01
#>  [5,] -0.809017  5.877853e-01
#>  [6,] -1.000000  1.224647e-16
#>  [7,] -0.809017 -5.877853e-01
#>  [8,] -0.309017 -9.510565e-01
#>  [9,]  0.309017 -9.510565e-01
#> [10,]  0.809017 -5.877853e-01

Created on 2025-07-05 with reprex v2.1.1

@schochastics
Copy link
Contributor Author

Then let's make it happen. I could adapt the plot code to also check for a vertex layout attribute

@szhorvat
Copy link
Member

szhorvat commented Jul 5, 2025

There are some issue with this approach. Since vector attributes are not supported in C yet, it will not be possible to export these to the standard formats such as GML.

In the long term it would be good to do this, but I'm wondering if it's a better approach to wait until the C core supports it, or at least wait until upgrading to C/igraph 1.0. I have an issue open for this here: igraph/igraph#2744 Realistically, we probably won't have the capacity to make it happen for 1.0, but I'd like to be optimistic and take another look ...

@szhorvat
Copy link
Member

szhorvat commented Jul 5, 2025

(To be clear, IMO this is absolutely the right way to do it. My concern is making this an R-specific feature, especially before we had the opportunity to take a good look at it in C and determine what interface is feasible.)

@krlmlr
Copy link
Contributor

krlmlr commented Jul 5, 2025 via email

@krlmlr
Copy link
Contributor

krlmlr commented Jul 5, 2025 via email

@szhorvat
Copy link
Member

szhorvat commented Jul 5, 2025

How I envisioned this working was exactly V(g)$layout <- matrix, and internally, in C, such an attribute would be stored precisely as a matrix. Some of the concerns I have, that I think we need to think through, are:

  • Issue with columns-major vs row-major storage in C. @krlmlr, can you confirm that R uses column-major (just like igraph)?
  • How well this fits various file formats?
  • We had some discussions with @ntamas about proposing a new format, but now that the NASCOL forum is dead (CC @vtraag) this'll be harder to push through.

And of course the biggest issue: Implementing this feature with the very limited capacity we have ...

@szhorvat
Copy link
Member

szhorvat commented Jul 5, 2025

How about going with @krlmlr's design, and setting the layout fixed-length vector attribute, just as you proposed, but also providing a feature (i.e. a conveniene function) to convert between the layout and x/y formats? This would make it easy for people to convert to a format that is easily exportable with the current features.

@schochastics
Copy link
Contributor Author

Would this be a separate PR?
I feel like the scope of this PR is only to provide a warning/error for layouts as graph attributes. A separate PR would be to allow layout as node attribute + conversion?
Happy to put this all into this PR though if that is fine

@krlmlr
Copy link
Contributor

krlmlr commented Jul 7, 2025

Let's turn this into an error then, and address the other topics later.

@schochastics
Copy link
Contributor Author

@krlmlr ok to merge if everything passes?

@krlmlr krlmlr changed the title fix: add warning if layout doesnt match number of vertices fix: Fail if "layout" attribute doesn't match the number of vertices Jul 7, 2025
@krlmlr krlmlr enabled auto-merge (squash) July 7, 2025 12:47
@krlmlr
Copy link
Contributor

krlmlr commented Jul 7, 2025

Thanks, merging.

@krlmlr krlmlr merged commit 017c0f2 into main Jul 7, 2025
6 checks passed
@krlmlr krlmlr deleted the f-layout-graph-attr branch July 7, 2025 12:51
krlmlr added a commit that referenced this pull request Oct 13, 2025
igraph 2.2.0

Update C core to version 0.10.17. See <https://github.com/igraph/rigraph/blob/20552ef94aed6ae4b23465ae8c7e4d3b0e558c71/src/vendor/cigraph/CHANGELOG.md> for a complete changelog, in particular the section "Breaking changes".

- Generate almost all R implementations (#2047).

- Expose `align_layout()` and add to `layout_nicely()` to align layout with axis automatically (#1907, #1957, #1958).

- Expose `simple_cycles()` which lists all simple cycles (#1573, #1580).

- Expose `is_complete()`, `is_clique()` and `is_ivs()` (#1316, #1388, #1581).

- Expose `find_cycle()` (#1471, #1571).

- Expose `feedback_vertex_set()` to find a minimum feedback vertex set in a graph (#1446, #1447, #1560).

- Add `weights` parameter to `local_scan()` (#1082, #1448, #1982).

- Add more layouts to `tkplot()` (#160, #1967).

- Add `plot(mark.lwd = )` to change line width of mark.groups (#306, #1898).

- Add `plot(vertex.label.angle = , vertex.label.adj = )` arguments to rotate vertex labels (#106, #1899).

- Add relative size scaling to vertices in `plot()` (@gvegayon, #172).

- Split `sample_bipartite()` into two functions for the G(n, m) and G(n, p) case (#630, #1692).

- Implement multi attribute assignment (#55, #1916) and adding attributes via data frames (#1373, #1669, #1716). Support factors in `graph_from_data_frame()` (#34, #1829).

- All `_hrg()` functions check their argument (#1074, #1699).

- HRG printing with `type = "auto"` uses `"plain"` for large trees (#1879).

- `get_edge_ids()` accepts data frames and matrices (#1663).

- `igraph_version()` returns version of C core in an attribute (#1208, #1781).

- Breaking change: change arguments default and order for `graph_from_lcf()` (#1858, #1872).

- Breaking change: Subset assignment of a graph avoids addition of double edges and ignores loops unless the new `loops` argument is set to `TRUE` (#1662, #1661).

- Breaking change: remove deprecated `neimode` parameter from `bfs()` and `dfs()` (#1105, #1526).

- Breaking change: stricter deprecation of non-functional parameters of `layout_with_kk()` and `layout_with_fr()` (#1108, #1628).

- `NA` attribute values are replaced with default values in `plot()` (#293, #1707).

- `NA` checking only in from/to columns of edge data frame (#1906).

- Keep vertex attribute type for `disjoint_union()` (#1640, #1909).

- Error in bipartite projection if `type` is not a vertex attribute (#898, #1889).

- Do not try to destroy non-initialized SIR objects upon error (#1888).

- Added proper `NA` handling for matrix inputs (#917, #918, #1828).

- Remove string matrix support from functions operating on biadjacency matrices (#1540, #1542, #1803).

- Integer vectors are validated before transferring them to the C library (#1434, #1582).

- Changed base location for `graph_from_graphdb()` and added tests (#1712, #1732).

- Recycling of logical vectors when indexing into edge/vertex selectors now throws an error (#848, #1731).

- Use `function()` instead of `(x)` in `arrow.mode` (#1722).

- Temporarily disable generating an interface for `igraph_simple_cycles_callback()` as the framework for handling callback functions is not yet present.

- Adjust loop position to vertex size in `plot()` (#1980).

- Don't rescale plot coordinates to `[-1,1] x [-1,1]` by default (#1492, #1956, #1962).

- Fail if `"layout"` attribute doesn't match the number of vertices (#1880).

- Automatically arrange loops in `plot()` (#407, #556, #1881).

- Vectorized drawing of arrows in `plot()` (#257, #1904).

- Allow more than one edge label font family in `plot()` (#37, #1896).

- Pie shapes now work as intended (#1882, #1883).

- Loops not plotted on canvas (#1799, #1800).

- Replace `NA` values in `label` attributes in `plot()` with default values (#1796, #1797).

- Removed duplicated plotting of arrow heads (#640, #1709).

- Correct mapping of edge label properties in plots when loops are present (#157, #1706).

- Welcome Maëlle Salmon and David Schoch as authors (#1733), add author links (#1821).

- Remove demos (#2008).

- Add 2023 preprint (#1240, #1984).

- Update allcontributors info (#1975).

- Link to replacements of deprecated functions (#1823).

- Add documentation of all file formats to `read_graph()` and `write_graph()` (#777, #1969). Recommend `saveRDS()` and `readRDS()` for saving and loading graphs (#1242, #1700).

- Document return value of `make_clusters()` (#1794).

- Clarify that `girth()` returns `Inf` for acyclic graphs (@eqmooring, #1831).

- Clarify the use of weights in `layout_with_kk()`.

- Refer to current latest version of R in troubleshooting page.

- Fix typos in `laplacian_matrix()` documentation.

- Document ellipsis in `cohesion()` (#971, #1985).

- Correct the description of the `weights` parameter of `hits_scores()`.

- Better describe output of `all_shortest_paths()` (#1029, #1778).

- `make_graph()` now supports `"Groetzsch"` as an alias of `"Grotzsch"`. This change was implemented in the C core.

- Update description of `order` parameter of `ego()` and related functions (#1746).

- Added lifecycle table (#1525).

- Add more about igraph.r2cdocs in the contributing guide (#1686, #1697).

- Accelerate check if an index sequence corresponds to the entire list of vertices (#1427, #1818).

- Faster single bracket querying of a graph (#1465, #1658).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hackathon-topic 📆 plotting 💹 Issues related to plotting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants