Skip to content

Conversation

@schochastics
Copy link
Contributor

@schochastics schochastics commented Jun 24, 2025

fix #407
fix #556

devtools::load_all("~/git/R_packages/rigraph/")
#> ℹ Loading igraph
g1 <- make_graph(c(1, 1))
g2 <- make_graph(c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1))
plot(g1)

plot(g2, margin = 0.1)

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

@schochastics schochastics requested a review from szhorvat June 24, 2025 09:15
@szhorvat
Copy link
Member

This is definitely an improvement over the current situation, but I'd consider it a makeshift solution until something like this can be implemented:

image

This show the issues better:

g2 <- make_graph(c(1,2, 2,3, 3,1, 1,4, 4,5, 5,1, 3,4, 5,2, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1))
plot(g2)
image

Problems:

  • By adding more loops, the loop sizes grow, eventually intersecting edges.
  • The loop direction seems fixed, so it even intersects edges that are incident to the loop's own vertex. Thus for a high quality solution, it is unavoidable to determine "where the loops fits" between the other incident edges of a vertex. At that point, having different angles for different loops is a small addition.

Compare:

image

More plots:

g2 <- make_graph(c(1,2, 2,3, 3,1, 1,4, 4,5, 5,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1))
plot(g2)
image

@szhorvat
Copy link
Member

In short: I would merge this, as it is an improvement, but I disagree with closing #407, as it's not a complete fix.

@schochastics
Copy link
Contributor Author

Thanks. I will have a look if I can implement an angle version instead and otherwise I would merge as is

@szhorvat
Copy link
Member

I will have a look if I can implement an angle version

The examples I showed are from Mathematica, but the angle version is implemented in Python as well, so that might be a useful reference.

I think doing this might be quite a bit of work. IMO it'd make sense to merge the improvement in this PR, as it's already much better than the current situation. Further improvements can always come later.

@schochastics
Copy link
Contributor Author

schochastics commented Jun 24, 2025

You are right that these seems complicated. But the least that I will try is to place the loops more smartly in free space. This does not look very nice

library(igraph)
g <- make_graph(c(1,2,2,3,3,1,1,1,1,1,1,1,1,1),directed = FALSE)
V(g)$x <- c(1,1.5,2)
V(g)$y <- c(0,1,0)
plot(g,margin = 0.1)

devtools::load_all("~/git/R_packages/rigraph")
#> ℹ Loading igraph
plot(g,margin = 0.1)

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

I am aware of edge.loop.angle, but this should probably be possible to calculate dynamically

@schochastics
Copy link
Contributor Author

Getting closer. loops are now placed in the largest gap available. Need to adjust the handling of edge.loop.angle. Idea: default to NA to use dynamic calculation.

devtools::load_all("~/git/R_packages/rigraph")
#> ℹ Loading igraph

g2 <- make_graph(c(1,2, 2,3, 3,1, 1,4, 4,5, 5,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1))
plot(g2)

g2 <- make_graph(c(1,2, 2,3, 3,1, 1,4, 4,5, 5,1, 3,4, 5,2, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1))
plot(g2)

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

@schochastics
Copy link
Contributor Author

@szhorvat how is this? Might need some parameter tweaking but I think overall it seems fine

devtools::load_all("~/git/R_packages/rigraph")
#> ℹ Loading igraph

g <- make_graph(c(1,2,2,3,3,1,1,1,1,1,1,1,1,1),directed = FALSE)
V(g)$x <- c(1,1.5,2)
V(g)$y <- c(0,1,0)
plot(g,margin = 0.2,loop.size=2)

g2 <- make_graph(c(1,2, 2,3, 3,1, 1,4, 4,5, 5,1, 3,4, 5,2, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1),directed = FALSE)
plot(g2,loop.size = 2)

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

@schochastics
Copy link
Contributor Author

need to fix label placement

@szhorvat
Copy link
Member

Awesome! Does the loop angular width depend on the loop count and available angular space? Or it if fixed? (No time to compile and test until evening today.)

@schochastics
Copy link
Contributor Author

Currently depending only on the loop count. I still have to make it adapt to the available space too

@szhorvat
Copy link
Member

szhorvat commented Jun 25, 2025

A nitpick (don't take it too seriously):

Ideally, the lines would converge on the centre of the node. They should not touch on the boundary of the node.

image

Do test with square node shapes if you haven't yet! There were bugs in the past with this shape.

@szhorvat
Copy link
Member

Do you think it's a good idea to keep the original version (loops within loops) as an option? I haven't seen this style before. It's not actually bad, it's just different. Once the loop is fit in the largest space (which you implemented), it could be an interesting option.

@schochastics
Copy link
Contributor Author

Now its implemented. Will check on the nitpick and rectangular nodes.
You mean you havent seen the "loop in loop" before? I actually have never seen the "flower pedals" style before! Personally, I think we should decide on one style. I am fine with the "pedals". Keeping both makes the already convoluted plotting code even worse.

@schochastics
Copy link
Contributor Author

schochastics commented Jun 25, 2025

Ok I think we might be done now with the main tasks (I will try to tweak the needed parameters a bit to make it a little nicer)

devtools::load_all("~/git/R_packages/rigraph")
#> ℹ Loading igraph

g <- make_graph(c(1,2,2,3,3,1,1,1,1,1,1,1,1,1),directed = FALSE)
V(g)$x <- c(1,1.5,2)
V(g)$y <- c(0,1,0)
plot(g,margin = 0.4,loop.size = 2, vertex.size=10)

g2 <- make_graph(c(1,2, 2,3, 3,1, 1,4, 4,5, 5,1, 3,4, 5,2, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1),directed = FALSE)
plot(g2,loop.size = 2,vertex.shape="rectangle")

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

@schochastics
Copy link
Contributor Author

schochastics commented Jun 25, 2025

I dont understand where these errors come from 😞
Error is legit, need to fix

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

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, let's strive for consistency.

@schochastics schochastics changed the title fix: adjust loop size for multi loops fix: automatically arrange loops in plot() Jul 3, 2025
@schochastics schochastics enabled auto-merge (squash) July 3, 2025 10:15
@schochastics schochastics merged commit bd82033 into main Jul 3, 2025
6 checks passed
@schochastics schochastics deleted the f-multi-loop branch July 3, 2025 10:30
schochastics added a commit that referenced this pull request Aug 25, 2025
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: schochastics <[email protected]>
Co-authored-by: schochastics <[email protected]>
Co-authored-by: Kirill Müller <[email protected]>
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

plotting 💹 Issues related to plotting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nice to have: Plot self-loops so that they face away from other edges Plotting: multiple self-loops on a vertex are plotted on top of each other

4 participants