diff --git a/DESCRIPTION b/DESCRIPTION index 45c8def..17a4405 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: manynet Title: Many Ways to Make, Manipulate, and Map Myriad Networks -Version: 0.1.1 -Date: 2023-06-09 +Version: 0.2.1 +Date: 2023-08-11 Description: A set of tools for making, manipulating, and mapping many different types of networks. All functions operate with matrices, edge lists, and 'igraph', 'network', and 'tidygraph' objects, and on one-mode, two-mode (bipartite), and sometimes three-mode networks. @@ -16,9 +16,12 @@ Language: en-GB Encoding: UTF-8 LazyData: true RoxygenNote: 7.2.3 -Imports: dplyr (>= 1.1.0), ggplot2, ggraph, igraph, network, tidygraph +Imports: dplyr (>= 1.1.0), ggplot2, ggraph, igraph (>= 1.5.0.1), + network, tidygraph Suggests: gganimate, methods, readxl, roxygen2, RSiena, testthat, xml2, - patchwork + patchwork, knitr, rmarkdown, learnr, grDevices, BiocManager, + minMSE +Enhances: Rgraphviz Authors@R: c(person(given = "James", family = "Hollway", @@ -31,10 +34,10 @@ Authors@R: comment = c("IHEID", ORCID = "0000-0003-3420-6085")) ) NeedsCompilation: no -Packaged: 2023-06-09 19:19:24 UTC; hollway +Packaged: 2023-08-11 13:07:02 UTC; hollway Author: James Hollway [cre, aut, ctb] (IHEID, ), Henrique Sposito [ctb] (IHEID, ) Maintainer: James Hollway Repository: CRAN -Date/Publication: 2023-06-10 14:10:02 UTC +Date/Publication: 2023-08-11 13:40:06 UTC diff --git a/MD5 b/MD5 index 203eb88..83ee9b9 100644 --- a/MD5 +++ b/MD5 @@ -1,74 +1,87 @@ -e04df197c3973e41ae8f02d5556370f4 *DESCRIPTION +5682971c475d8f91198989f247d133f8 *DESCRIPTION 361d71c6379f4ddf09ca9c8540b8fea1 *LICENSE -a5911dbf4336555dd6a6aa44bc5ea148 *NAMESPACE -f9a53402f2ff37b9056d6da863781480 *NEWS.md -07862752f654a6b5fab5747f262333c7 *R/data_ison.R -e556f016e1bfbb7cf79c6671ad3c6496 *R/make_as.R -012799866b6d02a5b9fe79e0dfd53641 *R/make_create.R -255913aacc10bf6b4a8161c306472e01 *R/make_generate.R -724942ce45d78b981e435f2359eaf3c4 *R/make_read.R -2f5f2a17d6765a1b83bbd3ff8d8b34d3 *R/manip_add.R +3ab8ea40ca6fbb3728177c8ca0f1255c *NAMESPACE +53e5898f3d3fc9f59be9822e0bdd9bda *NEWS.md +65446f8db7ac66243fe0e2bd445d6076 *R/data_ison.R +9022cd74ad3f3e6b31705c7555e23567 *R/make_as.R +280195557bbe3c28bd67cde1f5423490 *R/make_create.R +a59dcc247a1aa29833f174ec2529cb10 *R/make_generate.R +50f2dd264d63cab1914f5fbaaecdf5fc *R/make_read.R +eaf9a4357387f0e949880e03221472dd *R/manip_add.R 53c02b0642c4c2bd507849f3a6f67eb3 *R/manip_from.R e9aad6f23cbc1657f3281237185c8908 *R/manip_miss.R -823f4995631499e5d62ad5e8d607ef7f *R/manip_reformat.R -b36b2b5c8e39a8bded9b8b6bd88ec9a5 *R/manip_split.R +c86f435854b50d81a7d318ba60ca7897 *R/manip_reformat.R +62f53c3ab0913ff606b0a9eafed507e6 *R/manip_split.R 29095322bb905d8551d7577e09a1a815 *R/manip_tidy.R -ced0b300d36bf5fb15fefd9673339654 *R/manip_transform.R +9fe01dbfe1df9c4b0e060de9713c6e2a *R/manip_transform.R +e6904ca7fa87c64684580f5b36e5896d *R/manynet-utils.R 5a485b8100c0667e5fdd249c345a4bff *R/map_attributes.R -c50170af7c78422278779fb8a3f3a470 *R/map_autographr.R -6d977bd802739cf2c9e3a0d61346bfde *R/map_is.R -b5cb63b61c31bae010269a0428be600a *R/map_palette.R +f672ad16ae8ecdf382b6c2bfdcb2f065 *R/map_autographr.R +262ac6411f46c6a8eea206024cfc863c *R/map_is.R +27ed31b66230cc7bdea828a439f57b6a *R/map_layout_partition.R +97a8d4d39163df53cbafb9a63b3d3610 *R/map_palettes.R +46ee795018bd813bbe3f27b336e8a5f2 *R/map_plot.R 79cd003ad6cc4e2ce5a4fccf8362ec5e *R/map_properties.R +6055b3efe87103c679152199faca4039 *R/map_theme.R 0282c7ecc85fa60c7d6b987991fb2766 *R/print_classes.R 33162022353ceac96f9282149c710d90 *R/reexports_classes.R 5b6bdf57abcbb9776d5b05ae9d0c1192 *R/reexports_ggplot2.R c32b17bf67aaa82f9497832d48ffc8b1 *R/sysdata.rda -fc57376219f96dce9629f67605989b36 *README.md +20c5d0ac9aba30fa26730845f310eb3a *README.md 439bf689fa27cf9affd0335332142165 *build/partial.rdb -ab1a6ec9a34fe6a5bf2e48b6e31b812d *data/ison_adolescents.rda -e7517b200211dee8211dc5c7f9de5d93 *data/ison_algebra.rda -e2293da3b0ad4848864ef3f29a92e8fe *data/ison_bb.rda -f05ce9a742cef580057e41cbfce5fe04 *data/ison_bm.rda -deec7106bb20cbb1684a839dbc82c46d *data/ison_brandes.rda -eded5dc00a8c023ac8c7eabe1bea006b *data/ison_brandes2.rda -60ebf5b48615b183674db8cd15bbcfe5 *data/ison_karateka.rda -09ca699f6f4b224b7d575976f89c1d83 *data/ison_lotr.rda +165a53aa74d16bf17d9476a4cdca3567 *data/ison_adolescents.rda +e5b3237a16d54a8fc774b8d8128fed39 *data/ison_algebra.rda +b20354b3d6f9fb3b4e65c511ed5db78a *data/ison_brandes.rda +41a221361a130d269ba1a91788ab2922 *data/ison_karateka.rda +8250e638e7ae6c2299e8f831eab0a82e *data/ison_konigsberg.rda +ffe9cca1f76c1fe8bc16265b57da49f7 *data/ison_laterals.rda +93e366676084deeb1faa88333b54a6a3 *data/ison_lotr.rda 3d49ca0a38656ff2f38a9f8cb5bd3ef8 *data/ison_marvel_relationships.rda 0283024d033581ff0e9dcab5f05d0e54 *data/ison_marvel_teams.rda -7949d965942488ef7dd7635fc077d12f *data/ison_mb.rda -1071c1e04efedc84a2ffb92ad8730bca *data/ison_mm.rda -b4526aa0a2b750bd7bddf3203e57418b *data/ison_networkers.rda -f3c662b4d956f9f2f6cfb06ae7969687 *data/ison_southern_women.rda +e327b78dbf21f748a1fe54322c93e496 *data/ison_networkers.rda +b45178a091e0cdb0ab2ba12abaf63e4e *data/ison_southern_women.rda a8b18fd3012e113ac1533d3e43e28d02 *inst/manynet.png -651df2e144877e838318b951764b3290 *man/add.Rd -506fc6aef5f19d2c5b75ca05caf3bf60 *man/as.Rd -88fa55712881eb81a63bcd823f3f95ba *man/attributes.Rd -77bbfdb675c3e6e8dae95ea57c0cc4f0 *man/auto_graph.Rd -8d7f9be221099fd8ebcc2eac39ece6c0 *man/create.Rd +8316307638b5e9cbf37d88e864ab2b78 *inst/tutorials/tutorial1/data.Rmd +fb00940f1411f89fe46a9c062a62fb81 *inst/tutorials/tutorial1/data.html +e6611f534f1efb2d9df7fb51777f93d9 *inst/tutorials/tutorial1/data/adols.csv +52bb5bccd9a3b7d3dbbc28794a9b64f8 *inst/tutorials/tutorial1/data/adols.net +52bb5bccd9a3b7d3dbbc28794a9b64f8 *inst/tutorials/tutorial1/data/adols.paj +dbd302bd9c1e2c921c6255d740ca5c0b *inst/tutorials/tutorial1/data/flonode.csv +34920856cbb0b2a30fde9fabd2a04b6e *inst/tutorials/tutorial2/visualisation.Rmd +9223598f303d76d65360a723ab81f1e6 *inst/tutorials/tutorial2/visualisation.html +2ed79662b1c293c0be2edceb47c1aa5d *inst/tutorials/tutorial2/visualisation_files/figure-html/maxbet-1.png +577785c00b8026d2e5400086537611cb *man/add.Rd +daadf1d5c685eba1af39e765c9a13ae6 *man/as.Rd +07182262c8dd174e4ba6657bc589d6cb *man/attributes.Rd +a00c21113d63e8f5b8ade9ba189a70db *man/auto_graph.Rd +d820a2ec1e34da685561d025a0185fd0 *man/create.Rd d2f6ba1c56e762bdd6893dd3e87b3386 *man/figures/README-coercion-graph-1.png -ff360d399b958b17bd2ff2812bdaa42e *man/figures/README-import-graph-1.png -e4cb423af93516a7f314cea9e6619aa4 *man/figures/README-layout-comparison-1.png +34076488ddf8d5fcab83b9b25dffc725 *man/figures/README-import-graph-1.png +4aa3a28863f403109d42ab15aa6534da *man/figures/README-layout-comparison-1.png ca331d67c1914f18ff55433134498306 *man/figures/logo.png -42b92171886daeccf6d3aa298c38701c *man/from.Rd -c3a170d1ea76b0df63867b4722f9340e *man/generate.Rd -328a68a60e068293ed4eb2e539326267 *man/is.Rd +955258e5212728cea3c637a208ce7fb6 *man/from.Rd +ec6f767d4a16ce9affc08e855ab399bd *man/generate.Rd +be0945ab0eea0c4e2efd09161317a5e8 *man/is.Rd c87ee7ae255f81a25c605d7a592e411a *man/ison_adolescents.Rd b23963ab1fa2d335889796aff99766df *man/ison_algebra.Rd -f747adbd19c68d8e2d03e545e32de8b0 *man/ison_brandes.Rd +abb742a15b0d42220fdf1a9842343908 *man/ison_brandes.Rd 641f9e92c6a5a93938cb11af8f6680a2 *man/ison_karateka.Rd +3d3dae69f6654d22e5f1a3d769e95186 *man/ison_konigsberg.Rd +d2b34f7444de9f5f84b4194c4be507c4 *man/ison_laterals.Rd 363a5584ba45f3d348b54de3ec6e37f1 *man/ison_lotr.Rd -39018588f2ad52520528dcd51b837989 *man/ison_marvel.Rd +872d6ffc4b2e0e3593bfff2c44ecf12d *man/ison_marvel.Rd 8af25118b798ee1918429e28c169580f *man/ison_networkers.Rd -1075e2328ca3f0058678fdeeb55c4dde *man/ison_projection.Rd 489b7ee3f4807dc597cd78f6fa5d92a7 *man/ison_southern_women.Rd -0a7f2779e1b7388e666eaf5ed2f7365d *man/miss.Rd -a1b95c80ffd2e627366a9906b96168b5 *man/properties.Rd -39980ed922e20755e4f39e6f9b0f0c6d *man/read.Rd +f5cd8e08542281e8877896bb2f1e2679 *man/miss.Rd +f64eb245d4747839e5d137af2f8ffd1b *man/partition_layouts.Rd +389ed0f7a8c898a6f4e51eae2e4dedb6 *man/properties.Rd +83afbd68939135cccb533a3d78dfe13c *man/read.Rd 74cd9b0a7752d1047ee138a8936950bd *man/reexports.Rd -b606898920d421c996fac53972fb439c *man/reformat.Rd -c77c85d1c6b8bdaa807f4dec8f811bfc *man/split.Rd -00bf620ca6b52bedf4abe6f13cd45b94 *man/tidy.Rd -eebda4001a386b8f3394f0d159c56e7d *man/transform.Rd +76dfe722f52ddcf2ba64725e261dfdf2 *man/reformat.Rd +98a4acacc3b543d909a6982eb1533054 *man/split.Rd +5aa570e908958357e0b8f0be069f4e5b *man/themes.Rd +1467c5cf3b719c40514260257c027b5b *man/tidy.Rd +862b995f8ce91e77fb4695e38f1c1762 *man/transform.Rd 594c90777a4f17666af95dce0dbb4d17 *tests/testthat.R 4a312f7e35283b4c0b85e800491103e5 *tests/testthat/sheets/SouthernWomen.paj 89a78d83fa6c80560955c6f2dc887e33 *tests/testthat/sheets/SouthernWomen.xml @@ -81,16 +94,17 @@ efec1c3e6d8f1ef526d40df7c87c0b56 *tests/testthat/sheets/test_matrix.csv 327266b6086e4cbea4f27a0f6b1dedbf *tests/testthat/sheets/ucinettest.##d bdd9ad82944ff4c6cc1171e853071012 *tests/testthat/sheets/ucinettest.##h bdd9ad82944ff4c6cc1171e853071012 *tests/testthat/sheets/ucinettest1.##h -496eab437fcbe3ac78f959136c46346a *tests/testthat/test-make_create.R +6e36522f661de1ec7c05f2b5d7493f34 *tests/testthat/test-make_create.R 9fa727b7cffe964ca8637cb47cd8341d *tests/testthat/test-make_generate.R cdbac54b8a56d7007e5696222d913847 *tests/testthat/test-make_read.R -4fe048fce4f3450cf2fe7be86a023909 *tests/testthat/test-manip_add.R +75c447fe8a95ea6707ced6fd999b4853 *tests/testthat/test-manip_add.R e704b7958c4e61614d5f3d6ca466fd46 *tests/testthat/test-manip_as.R b51f8cdc30203b9774ece4f36ec6bcea *tests/testthat/test-manip_grab.R b644d01d099d612cc806972a4ad28c84 *tests/testthat/test-manip_miss.R -ea203626cbfac1f80f543147fc87eda1 *tests/testthat/test-manip_reformat.R +d7a9db995bdb8e37043eec3b2614d23b *tests/testthat/test-manip_reformat.R 6a03770649c99095fb7a58a9ba04fd53 *tests/testthat/test-manip_split.R -004520bac4563e2121e419a055d7fbeb *tests/testthat/test-manip_transform.R -d4921f1bc37d27eafd013aa409199724 *tests/testthat/test-mark_is.R +47b2d9d25c1b81d27a4439995ac5f7c6 *tests/testthat/test-manip_transform.R +323d7aae6d20f03784af0c4da77b19ea *tests/testthat/test-map_autographr.R +d699c2b2e6326cd476b4f1539b22b53a *tests/testthat/test-map_is.R 805f7fd21fcb36696bce345246b6c741 *tests/testthat/test-print_class.R -fc83cd52c840f70a645b3da9a6f018b3 *tests/testthat/test-viz_autographr.R +04d5192ce082546e899ea7bb5250e7e4 *tests/testthat/test_plots.R diff --git a/NAMESPACE b/NAMESPACE index aa1b314..b22159d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -50,6 +50,7 @@ S3method(as_tidygraph,network) S3method(as_tidygraph,network.goldfish) S3method(as_tidygraph,siena) S3method(as_tidygraph,tbl_graph) +S3method(delete_nodes,igraph) S3method(is_complex,data.frame) S3method(is_complex,igraph) S3method(is_complex,matrix) @@ -140,6 +141,8 @@ S3method(to_egos,igraph) S3method(to_egos,matrix) S3method(to_egos,network) S3method(to_egos,tbl_graph) +S3method(to_eulerian,igraph) +S3method(to_eulerian,tbl_graph) S3method(to_giant,data.frame) S3method(to_giant,igraph) S3method(to_giant,matrix) @@ -262,11 +265,13 @@ export(bind_node_attributes) export(create_components) export(create_core) export(create_empty) +export(create_explicit) export(create_filled) export(create_lattice) export(create_ring) export(create_star) export(create_tree) +export(delete_nodes) export(filter_ties) export(from_egos) export(from_slices) @@ -284,16 +289,21 @@ export(guides) export(is.igraph) export(is.network) export(is.tbl_graph) +export(is_acyclic) +export(is_aperiodic) export(is_bipartite) export(is_complex) +export(is_connected) export(is_directed) export(is_dynamic) export(is_edgelist) +export(is_eulerian) export(is_graph) export(is_labelled) export(is_longitudinal) export(is_manynet) export(is_multiplex) +export(is_perfect_matching) export(is_signed) export(is_twomode) export(is_uniplex) @@ -301,6 +311,11 @@ export(is_weighted) export(join_nodes) export(join_ties) export(labs) +export(layout_tbl_graph_alluvial) +export(layout_tbl_graph_concentric) +export(layout_tbl_graph_hierarchy) +export(layout_tbl_graph_ladder) +export(layout_tbl_graph_railway) export(mutate) export(mutate_ties) export(na_to_mean) @@ -323,6 +338,7 @@ export(rename) export(rename_ties) export(select_ties) export(summarise_ties) +export(theme_iheid) export(tie_attribute) export(tie_signs) export(tie_weights) @@ -332,6 +348,7 @@ export(to_blocks) export(to_components) export(to_directed) export(to_egos) +export(to_eulerian) export(to_giant) export(to_matching) export(to_mode1) @@ -407,6 +424,7 @@ importFrom(ggraph,scale_edge_width_continuous) importFrom(igraph,E) importFrom(igraph,V) importFrom(igraph,add_edges) +importFrom(igraph,add_vertices) importFrom(igraph,any_multiple) importFrom(igraph,as.directed) importFrom(igraph,as.undirected) @@ -416,11 +434,14 @@ importFrom(igraph,as_incidence_matrix) importFrom(igraph,bipartite.projection) importFrom(igraph,complementer) importFrom(igraph,decompose) +importFrom(igraph,degree) importFrom(igraph,delete_edge_attr) importFrom(igraph,delete_edges) importFrom(igraph,delete_vertex_attr) +importFrom(igraph,delete_vertices) importFrom(igraph,edge_attr) importFrom(igraph,edge_attr_names) +importFrom(igraph,eulerian_path) importFrom(igraph,get.edgelist) importFrom(igraph,get.vertex.attribute) importFrom(igraph,graph_from_adjacency_matrix) @@ -428,6 +449,7 @@ importFrom(igraph,graph_from_data_frame) importFrom(igraph,graph_from_incidence_matrix) importFrom(igraph,gsize) importFrom(igraph,induced_subgraph) +importFrom(igraph,is.connected) importFrom(igraph,is.directed) importFrom(igraph,is.igraph) importFrom(igraph,is.loop) @@ -435,6 +457,7 @@ importFrom(igraph,is.named) importFrom(igraph,is.simple) importFrom(igraph,is.weighted) importFrom(igraph,is_bipartite) +importFrom(igraph,is_dag) importFrom(igraph,list.vertex.attributes) importFrom(igraph,make_ego_graph) importFrom(igraph,make_lattice) diff --git a/NEWS.md b/NEWS.md index bde1b0a..64d06c4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,58 @@ +# manynet 0.2.1 + +2023-08-11 + +## Map + +* Fixed documentation issues with map_palettes + +# manynet 0.2.0 + +2023-08-11 + +## Package + +* Closed #4 by adding `thisRequiresBio()` helper function to download Bioconductor packages +* Upgraded ison data to latest igraph specification + * Added `ison_konigsberg` for illustrating Seven Bridges of Konigsberg + * Removed `ison_brandes2` and added potential modal type as extra variable to `ison_brandes` + * Consolidated `ison_bb`, `ison_bm`, `ison_mb`, and `ison_mm` into a list of networks called `ison_laterals` + +## Make + +* Added `create_explicit()` for creating networks based on explicit nodes and ties + +## Manip + +* Added `delete_nodes()` for deleting specific nodes +* Added `to_eulerian()` function that returns a Eulerian path network, if available, from a given network + +## Map + +* Moved additional `is_` functions from `{migraph}` + * Added `is_connected()` to test if network is strongly connected + * Added `is_perfect_matching()` to test if there is a matching for every node in the network + * Added `is_eulerian()` to test whether there is a Eulerian path for a network + * Added `is_acyclic` to test whether network is a directed acyclic graph + * Added `is_aperiodic` to test whether network is aperiodic +* Added partition layouts + * Added `layout_tbl_graph_alluvial()` that places successive layers horizontally + * Added `layout_tbl_graph_concentric()`that places a "hierarchy" layout around a circle + * Added `layout_tbl_graph_hierarchy()` that layers the nodes along the top and bottom sequenced to minimise overlap + * Added `layout_tbl_graph_ladder()`that aligns nodes across successive layers horizontally + * Added `layout_tbl_graph_railway` that aligns nodes across successive layers vertically +* Added `theme_iheid()` function that themes graphs with colors based on the Geneva Graduate Institute + +# manynet 0.1.2 + +2023-06-20 + +## Package + +- Added tutorials for package + - Moved and updated "data" tutorial from `{migraph}` + - Moved and updated "visualisations" tutorial from `{migraph}` + # manynet 0.1.1 2023-06-09 diff --git a/R/data_ison.R b/R/data_ison.R index e8e27a9..8b5a727 100644 --- a/R/data_ison.R +++ b/R/data_ison.R @@ -64,46 +64,24 @@ #' ``` "ison_lotr" -# Projection #### +# Laterals #### #' Two-mode projection examples (Hollway 2021) #' #' @description -#' These datasets are for demonstration purposes and do not describe any real world network. +#' These networks are for demonstration purposes and do not describe any real world network. #' All examples contain named nodes. +#' The networks are gathered together as a list and can be retrieved simply by plucking +#' the desired network. #' @docType data #' @keywords datasets -#' @name ison_projection -#' @usage data(ison_mm) +#' @name ison_laterals +#' @usage data(ison_laterals) #' @format #' ```{r, echo = FALSE} -#' ison_mm +#' ison_laterals #' ``` -"ison_mm" - -#' @rdname ison_projection -#' @usage data(ison_bm) -#' @format -#' ```{r, echo = FALSE} -#' ison_bm -#' ``` -"ison_bm" - -#' @rdname ison_projection -#' @usage data(ison_mb) -#' @format -#' ```{r, echo = FALSE} -#' ison_mb -#' ``` -"ison_mb" - -#' @rdname ison_projection -#' @usage data(ison_bb) -#' @format -#' ```{r, echo = FALSE} -#' ison_bb -#' ``` -"ison_bb" +"ison_laterals" # Algebra #### @@ -187,6 +165,23 @@ #' ``` "ison_karateka" +# Konigsberg #### + +#' One-mode Seven Bridges of Konigsberg network (Euler 1741) +#' +#' @docType data +#' @keywords datasets +#' @name ison_konigsberg +#' @usage data(ison_konigsberg) +#' @references +#' Euler, Leonard. 1741. “Solutio problematis ad geometriam situs pertinentis.” +#' _Commentarii academiae scientiarum Petropolitanae_. +#' @format +#' ```{r, echo = FALSE} +#' ison_konigsberg +#' ``` +"ison_konigsberg" + # Networkers #### #' One-mode EIES dataset (Freeman and Freeman 1979) @@ -222,6 +217,8 @@ #' #' This network should solely be used #' for demonstration purposes as it does not describe a real network. +#' To convert into the two-mode version, +#' assign `ison_brandes %>% rename(type = twomode_type)`. #' @docType data #' @keywords datasets #' @name ison_brandes @@ -232,15 +229,6 @@ #' ``` "ison_brandes" -#' @rdname ison_brandes -#' @usage data(ison_brandes2) -#' @format -#' ```{r, echo = FALSE} -#' ison_brandes2 -#' ``` -"ison_brandes2" - - # Southern Women #### #' Two-mode southern women (Davis, Gardner and Gardner 1941) diff --git a/R/make_as.R b/R/make_as.R index d563b10..6903f33 100644 --- a/R/make_as.R +++ b/R/make_as.R @@ -750,14 +750,7 @@ as_siena <- function(.data, #' @export as_siena.igraph <- function(.data, twomode = FALSE) { - if (!requireNamespace("RSiena", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `RSiena` package is required. - Would you like to install `RSiena` from CRAN?")) { - utils::install.packages('RSiena') - } else { - stop("Please install `RSiena` from CRAN to coerce into RSiena data objects.") - } - } + thisRequires("RSiena") # First separate out the dependent ties nets <- igraph::edge_attr_names(as_igraph(.data)) ties <- unique(gsub("_t[0-9]","", nets)) @@ -814,14 +807,7 @@ setClass("graphAM", contains="graph", #' @export as_graphAM.matrix <- function(.data, twomode = NULL) { - if (!requireNamespace("RSiena", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `RSiena` package is required. - Would you like to install `RSiena` from CRAN?")) { - utils::install.packages('RSiena') - } else { - stop("Please install `RSiena` from CRAN to coerce into RSiena data objects.") - } - } + thisRequires("RSiena") methods::new("graphAM", adjMat = to_onemode(.data), edgemode = ifelse(is_directed(.data), "directed", "undirected")) } diff --git a/R/make_create.R b/R/make_create.R index 171e477..a5c6403 100644 --- a/R/make_create.R +++ b/R/make_create.R @@ -358,6 +358,107 @@ create_core <- function(n, directed = FALSE, membership = NULL) { } } +#' @describeIn create Creates a network based on explicitly +#' named nodes and ties between them. +#' @seealso [igraph::graph_from_literal()] which `create_explicit()` mostly just wraps. +#' `create_explicit()` will also accept character input and not just a formula though, +#' and will never simplify the result. +#' @examples +#' create_explicit(A -+ B, B -+ C, A +-+ C, D) +#' @export +create_explicit <- function(...){ + if(is.symbol(as.list(match.call())[-1][[1]])){ + mf <- stats::reformulate(...) + mf[[1]] <- NULL + } else mf <- as.list(match.call())[-1] + f <- function(x) { + if (is.call(x)) { + return(list(as.character(x[[1]]), lapply(x[-1], f))) + } + else return(NULL) + } + ops <- unlist(lapply(mf, f)) + if (all(ops %in% c("-", ":"))) { + directed <- FALSE + } + else if (all(ops %in% c("-", "+", ":"))) { + directed <- TRUE + } + else { + stop("Invalid operator in formula") + } + f <- function(x) { + if (is.call(x)) { + if (length(x) == 3) { + return(list(f(x[[2]]), op = as.character(x[[1]]), + f(x[[3]]))) + } + else { + return(list(op = as.character(x[[1]]), f(x[[2]]))) + } + } + else { + return(c(sym = as.character(x))) + } + } + ret <- lapply(mf, function(x) unlist(f(x))) + v <- unique(unlist(lapply(ret, function(x) { + x[names(x) == "sym"] + }))) + ret <- lapply(ret, function(x) { + res <- list() + for (i in seq(along.with = x)) { + if (x[i] == ":" && names(x)[i] == "op") { + } + else if (i > 1 && x[i - 1] == ":" && names(x)[i - + 1] == "op") { + res[[length(res)]] <- c(res[[length(res)]], unname(x[i])) + } + else { + res <- c(res, x[i]) + } + } + res + }) + edges <- numeric() + for (i in seq(along.with = ret)) { + prev.sym <- character() + lhead <- rhead <- character() + for (j in seq(along.with = ret[[i]])) { + act <- ret[[i]][[j]] + if (names(ret[[i]])[j] == "op") { + if (length(lhead) == 0) { + lhead <- rhead <- act + } + else { + rhead <- act + } + } + else if (names(ret[[i]])[j] == "sym") { + for (ps in prev.sym) { + for (ps2 in act) { + if (lhead == "+") { + edges <- c(edges, unname(c(ps2, ps))) + } + if (!directed || rhead == "+") { + edges <- c(edges, unname(c(ps, ps2))) + } + } + } + lhead <- rhead <- character() + prev.sym <- act + } + } + } + ids <- seq(along.with = v) + names(ids) <- v + res <- igraph::make_graph(unname(ids[edges]), + n = length(v), directed = directed) + res <- igraph::set_vertex_attr(res, "name", value = v) + as_tidygraph(res) +} + + # #' @rdname create # #' @details Creates a nested two-mode network. # #' Will construct an affiliation matrix, diff --git a/R/make_generate.R b/R/make_generate.R index 3b9137a..2b2269b 100644 --- a/R/make_generate.R +++ b/R/make_generate.R @@ -24,8 +24,10 @@ NULL #' _Publicationes Mathematicae_. 6: 290–297. #' @importFrom igraph sample_bipartite sample_gnp sample_gnm #' @examples -#' autographr(generate_random(12, 0.4)) -#' autographr(generate_random(c(6, 6), 0.4)) +#' generate_random(12, 0.4) +#' generate_random(c(6, 6), 0.4) +#' #autographr(generate_random(12, 0.4)) +#' #autographr(generate_random(c(6, 6), 0.4)) #' @export generate_random <- function(n, p = 0.5, directed = FALSE, with_attr = TRUE) { if(is_manynet(n)){ @@ -81,9 +83,12 @@ generate_random <- function(n, p = 0.5, directed = FALSE, with_attr = TRUE) { #' \doi{10.1038/30918}. #' @importFrom igraph sample_smallworld #' @examples -#' autographr(generate_smallworld(12, 0.025)) -#' autographr(generate_smallworld(12, 0.25)) -#' autographr(generate_smallworld(c(6,6), 0.025)) +#' generate_smallworld(12, 0.025) +#' generate_smallworld(12, 0.25) +#' generate_smallworld(c(6,6), 0.025) +#' #autographr(generate_smallworld(12, 0.025)) +#' #autographr(generate_smallworld(12, 0.25)) +#' #autographr(generate_smallworld(c(6,6), 0.025)) #' @export generate_smallworld <- function(n, p = 0.05, directed = FALSE, width = 2) { directed <- infer_directed(n, directed) @@ -108,10 +113,14 @@ generate_smallworld <- function(n, p = 0.05, directed = FALSE, width = 2) { #' _Science_ 286(5439):509–12. #' \doi{10.1126/science.286.5439.509}. #' @examples -#' autographr(generate_scalefree(12, 0.25)) -#' autographr(generate_scalefree(12, 1.25)) -#' autographr(generate_scalefree(c(12,6), 0.25)) -#' autographr(generate_scalefree(c(12,6), 1.25)) +#' generate_scalefree(12, 0.25) +#' generate_scalefree(12, 1.25) +#' generate_scalefree(c(12,6), 0.25) +#' generate_scalefree(c(12,6), 1.25) +#' #autographr(generate_scalefree(12, 0.25)) +#' #autographr(generate_scalefree(12, 1.25)) +#' #autographr(generate_scalefree(c(12,6), 0.25)) +#' #autographr(generate_scalefree(c(12,6), 1.25)) #' @export generate_scalefree <- function(n, p = 1, directed = FALSE) { directed <- infer_directed(n, directed) diff --git a/R/make_read.R b/R/make_read.R index c4778b3..483efa9 100644 --- a/R/make_read.R +++ b/R/make_read.R @@ -75,14 +75,7 @@ read_matrix <- function(file = file.choose(), out <- read.csv2(file, ...) # For EU } } else if (grepl("xlsx$|xls$", file)) { - if (!requireNamespace("readxl", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `readxl` package is required. - Would you like to install `readxl` from CRAN?")) { - utils::install.packages('readxl') - } else { - stop("Please install `readxl` from CRAN to read excel files.") - } - } + thisRequires("readxl") out <- readxl::read_excel(file, ...) } if((dim(out)[1]+1) == dim(out)[2]) @@ -134,14 +127,7 @@ read_edgelist <- function(file = file.choose(), out <- read.csv2(file, header = TRUE, ...) # For EU } } else if (grepl("xlsx$|xls$", file)) { - if (!requireNamespace("readxl", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `readxl` package is required. - Would you like to install `readxl` from CRAN?")) { - utils::install.packages('readxl') - } else { - stop("Please install `readxl` from CRAN to read excel files.") - } - } + thisRequires("readxl") out <- readxl::read_excel(file, ...) } out @@ -182,14 +168,7 @@ read_nodelist <- function(file = file.choose(), out <- read.csv2(file, header = TRUE, ...) # For EU } } else if (grepl("xlsx$|xls$", file)) { - if (!requireNamespace("readxl", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `readxl` package is required. - Would you like to install `readxl` from CRAN?")) { - utils::install.packages('readxl') - } else { - stop("Please install `readxl` from CRAN to read excel files.") - } - } + thisRequires("readxl") out <- readxl::read_excel(file, ...) } out @@ -562,14 +541,7 @@ write_ucinet <- function(.data, #' @importFrom dplyr bind_rows coalesce filter mutate select everything #' @export read_dynetml <- function(file = file.choose()) { - if (!requireNamespace("xml2", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `xml2` package is required. - Would you like to install `xml2` from CRAN?")) { - utils::install.packages('xml2') - } else { - stop("Please install `xml2` from CRAN to import DynetML files.") - } - } + thisRequires("readxl") name <- type <- nodeset <- target <- value <- NULL xmlfile <- xml2::read_xml(file) xmllist <- xml2::as_list(xmlfile) diff --git a/R/manip_add.R b/R/manip_add.R index 9e2f94c..8488582 100644 --- a/R/manip_add.R +++ b/R/manip_add.R @@ -4,6 +4,13 @@ #' These functions allow users to add nodes, ties, or attributes to the nodes or ties #' of a network. #' The `add_*()` functions operate similarly to in `{igraph}`. +#' +#' Not all functions have methods available for all object classes. +#' Below are the currently implemented S3 methods: +#' +#' ```{r, echo = FALSE, cache = TRUE} +#' knitr::kable(available_methods(c("add_nodes", "delete_nodes", "add_ties", "add_node_attribute", "add_tie_attribute"))) +#' ``` #' @family manipulations #' @inheritParams is #' @param attribute A named list to be added as tie or node attributes. @@ -17,9 +24,9 @@ #' @name add NULL -#' @describeIn add Add additional ties to a network +#' @describeIn add Add additional nodes to a network #' @param nodes The number of nodes to be added. -#' @importFrom igraph add_edges +#' @importFrom igraph add_vertices #' @export add_nodes <- function(.data, nodes, attribute = NULL) UseMethod("add_nodes") @@ -38,6 +45,16 @@ add_nodes.network <- function(.data, nodes, attribute = NULL){ as_network(add_nodes(as_igraph(.data), nodes, attribute)) } +#' @describeIn add Delete nodes in a network +#' @importFrom igraph delete_vertices +#' @export +delete_nodes <- function(.data, nodes) UseMethod("delete_nodes") + +#' @export +delete_nodes.igraph <- function(.data, nodes){ + igraph::delete_vertices(.data, v = nodes) +} + #' @describeIn add Add additional ties to a network #' @param ties The number of ties to be added or an even list of ties. #' @importFrom igraph add_edges diff --git a/R/manip_reformat.R b/R/manip_reformat.R index 0f7167c..465d605 100644 --- a/R/manip_reformat.R +++ b/R/manip_reformat.R @@ -3,27 +3,20 @@ #' Tools for reformatting networks, graphs, and matrices #' #' @description -#' These functions offer tools for reformatting migraph-consistent objects -#' (matrices, igraph, tidygraph, or network objects). -#' Unlike the `as_*()` group of functions, -#' these functions always return the same object type as they are given, -#' only transforming these objects' properties. -#' @details -#' Since some modifications are easier to implement for some objects than others, -#' here are the currently implemented modifications: +#' These functions offer tools for reformatting migraph-consistent objects +#' (matrices, igraph, tidygraph, or network objects). +#' Unlike the `as_*()` group of functions, +#' these functions always return the same object type as they are given, +#' only transforming these objects' properties. #' -#' | to_ | edgelists | matrices |igraph |tidygraph |network | -#' | ------------- |:-----:|:-----:|:-----:|:-----:|:-----:| -#' | unweighted | X | X | X | X | X | -#' | undirected | | X | X | X | X | -#' | redirected | X | X | X | X | | -#' | unsigned | X | X | X | X | | -#' | uniplex | | | X | X | | -#' | unnamed | X | X | X | X | X | -#' | named | X | X | X | X | X | -#' | simplex | | X | X | X | | -#' | onemode | | | X | X | | -#' | multilevel | | X | X | X | | +#' Not all functions have methods available for all object classes. +#' Below are the currently implemented S3 methods: +#' +#' ```{r, echo = FALSE, cache = TRUE} +#' knitr::kable(available_methods(c("to_uniplex", "to_undirected", "to_directed", "to_redirected", +#' "to_reciprocated", "to_acyclic", "to_unweighted", "to_unsigned", "to_unnamed", "to_named", +#' "to_simplex", "to_onemode", "to_multilevel", "to_twomode"))) +#' ``` #' @name reformat #' @family manipulations #' @inheritParams is diff --git a/R/manip_split.R b/R/manip_split.R index f2e40b8..0015c90 100644 --- a/R/manip_split.R +++ b/R/manip_split.R @@ -2,7 +2,14 @@ #' #' @description #' These functions offer tools for splitting manynet-consistent objects -#' (matrices, igraph, tidygraph, or network objects). +#' (matrices, igraph, tidygraph, or network objects) into lists of networks. +#' +#' Not all functions have methods available for all object classes. +#' Below are the currently implemented S3 methods: +#' +#' ```{r, echo = FALSE, cache = TRUE} +#' knitr::kable(available_methods(c("to_egos", "to_subgraphs", "to_components", "to_waves", "to_slices"))) +#' ``` #' @name split #' @family manipulations #' @inheritParams reformat @@ -20,7 +27,7 @@ NULL #' @importFrom igraph make_ego_graph #' @examples #' to_egos(ison_adolescents) -#' autographs(to_egos(ison_adolescents,2)) +#' #autographs(to_egos(ison_adolescents,2)) #' @export to_egos <- function(.data, max_dist = 1, diff --git a/R/manip_transform.R b/R/manip_transform.R index d897491..a01e9fb 100644 --- a/R/manip_transform.R +++ b/R/manip_transform.R @@ -3,23 +3,19 @@ #' Tools for transforming networks, graphs, and matrices #' #' @description -#' These functions offer tools for transforming migraph-consistent objects -#' (matrices, igraph, tidygraph, or network objects). -#' Transforming means that the returned object may have different dimensions -#' than the original object. -#' @details -#' Since some modifications are easier to implement for some objects than others, -#' here are the currently implemented modifications: +#' These functions offer tools for transforming migraph-consistent objects +#' (matrices, igraph, tidygraph, or network objects). +#' Transforming means that the returned object may have different dimensions +#' than the original object. #' -#' | to_ | edgelists | matrices |igraph |tidygraph |network | -#' | ------------- |:-----:|:-----:|:-----:|:-----:|:-----:| -#' | mode1 | X | X | X | X | X | -#' | mode2 | X | X | X | X | X | -#' | giant | X | X | X | X | X | -#' | subgraph | X | X | X | X | X | -#' | ties | X | X | X | X | X | -#' | blocks | X | X | X | X | X | -#' | matching | X | X | X | X | X | +#' Not all functions have methods available for all object classes. +#' Below are the currently implemented S3 methods: +#' +#' ```{r, echo = FALSE, cache = TRUE} +#' knitr::kable(available_methods(c("to_mode1", "to_mode2", +#' "to_giant", "to_subgraph", "to_ties", "to_blocks", +#' "to_matching", "to_eulerian", "to_anti", "to_no_isolates"))) +#' ``` #' @name transform #' @family manipulations #' @inheritParams reformat @@ -54,8 +50,10 @@ NULL #' @importFrom igraph bipartite.projection #' @importFrom stats cor #' @examples -#' autographr(to_mode1(ison_southern_women)) -#' autographr(to_mode2(ison_southern_women)) +#' to_mode1(ison_southern_women) +#' to_mode2(ison_southern_women) +#' #autographr(to_mode1(ison_southern_women)) +#' #autographr(to_mode2(ison_southern_women)) #' @export to_mode1 <- function(.data, similarity = c("count","jaccard","rand","pearson","yule")) UseMethod("to_mode1") @@ -228,7 +226,8 @@ to_subgraph.matrix <- function(.data, ...){ #' where the edges are the nodes #' @importFrom igraph make_line_graph E #' @examples -#' autographr(to_ties(ison_adolescents)) +#' to_ties(ison_adolescents) +#' #autographr(to_ties(ison_adolescents)) #' @export to_ties <- function(.data) UseMethod("to_ties") @@ -348,7 +347,8 @@ to_blocks.tbl_graph <- function(.data, membership, FUN = mean){ #' By default "type". #' @importFrom igraph max_bipartite_match #' @examples -#' autographr(to_matching(ison_southern_women)) +#' to_matching(ison_southern_women) +#' #autographr(to_matching(ison_southern_women)) #' @export to_matching <- function(.data, mark = "type") UseMethod("to_matching") @@ -385,12 +385,42 @@ to_matching.matrix <- function(.data, mark = "type"){ as_matrix(to_matching(as_igraph(.data), mark)) } +#' @describeIn transform Returns a network with only +#' the Eulerian path +#' @importFrom igraph eulerian_path +#' @examples +#' to_eulerian(delete_nodes(ison_konigsberg, "Lomse")) +#' #autographr(to_eulerian(delete_nodes(ison_konigsberg, "Lomse"))) +#' @export +to_eulerian <- function(.data) UseMethod("to_eulerian") + +#' @export +to_eulerian.igraph <- function(.data){ + if(!is_eulerian(.data)) + stop("This is not a Eulerian graph.") + out <- paste(attr(igraph::eulerian_path(.data)$vpath, "names"), + collapse = "-+") + out <- create_explicit(out) + as_igraph(out) +} + +#' @export +to_eulerian.tbl_graph <- function(.data){ + if(!is_eulerian(.data)) + stop("This is not a Eulerian graph.") + out <- paste(attr(igraph::eulerian_path(.data)$vpath, "names"), + collapse = "-+") + out <- create_explicit(out) + out +} + #' @describeIn transform Returns the complement of a network #' where only ties _not_ present in the original network #' are included in the new network. #' @importFrom igraph complementer -#' @examples -#' autographr(to_anti(ison_southern_women)) +#' @examples +#' to_anti(ison_southern_women) +#' #autographr(to_anti(ison_southern_women)) #' @export to_anti <- function(.data) UseMethod("to_anti") diff --git a/R/manynet-utils.R b/R/manynet-utils.R new file mode 100644 index 0000000..86f425d --- /dev/null +++ b/R/manynet-utils.R @@ -0,0 +1,33 @@ +# Helper function for declaring available methods +available_methods <- function(fun_vctr) { + out <- lapply(fun_vctr, function(f) regmatches(utils::.S3methods(f), + regexpr("\\.", utils::.S3methods(f)), + invert = TRUE)) + out <- out[lapply(out,length)>0] + out <- t(as.data.frame(out)) + colnames(out) <- c("from","to") + rownames(out) <- NULL + out <- as.data.frame(out) + as_matrix(out) +} + +# Helper function for checking and downloading packages +thisRequires <- function(pkgname){ + if (!requireNamespace(pkgname, quietly = TRUE)) { + if(utils::askYesNo(msg = paste("The", pkgname, + "package is required to run this function. Would you like to install", pkgname, "from CRAN?"))) { + utils::install.packages(pkgname) + } else { + stop(paste("Please install", pkgname, "from CRAN to run this function.")) + } + } +} + +thisRequiresBio <- function(pkgname) { + if (!requireNamespace(pkgname, quietly = TRUE)) { + if(utils::askYesNo(msg = paste("The", pkgname, + "package is required to run this function. Would you like to install", pkgname, "from BioConductor?"))) { + thisRequires("BiocManager") + BiocManager::install(pkgname) + }} +} diff --git a/R/map_autographr.R b/R/map_autographr.R index 698f4a6..3fa0b2c 100644 --- a/R/map_autographr.R +++ b/R/map_autographr.R @@ -39,14 +39,14 @@ NULL #' @describeIn auto_graph Graphs a network with sensible defaults #' @examples -#' ison_adolescents %>% -#' mutate(shape = rep(c("circle", "square"), times = 4), -#' color = rep(c("blue", "red"), times = 4)) %>% -#' autographr(node_shape = "shape", node_color = "color") -#' autographr(ison_karateka, node_size = 8) +#' #ison_adolescents %>% +#' # mutate(shape = rep(c("circle", "square"), times = 4), +#' # color = rep(c("blue", "red"), times = 4)) %>% +#' # autographr(node_shape = "shape", node_color = "color") +#' #autographr(ison_karateka, node_size = 8) #' @export autographr <- function(.data, - layout = "stress", + layout = NULL, labels = TRUE, node_color = NULL, node_shape = NULL, @@ -62,7 +62,8 @@ autographr <- function(.data, # mutate(node_group = node_group) # } # Add layout ---- - p <- .graph_layout(g, layout, labels) + layout <- .infer_layout(g, layout) + p <- .graph_layout(g, layout, labels, ...) # Add edges ---- p <- .graph_edges(p, g, edge_color) # Add nodes ---- @@ -75,17 +76,10 @@ autographr <- function(.data, #' @param netlist A list of migraph-compatible networks. #' @source http://blog.schochastics.net/post/animating-network-evolutions-with-gganimate/ #' @examples -#' autographs(to_egos(ison_adolescents)) +#' #autographs(to_egos(ison_adolescents)) #' @export autographs <- function(netlist, ...) { - if (!requireNamespace("patchwork", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `patchwork` package is required. - Would you like to install `patchwork` from CRAN?")) { - utils::install.packages('patchwork') - } else { - stop("Please install `patchwork` from CRAN to graph multiple plots.") - } - } + thisRequires("patchwork") if(!is.null(names(netlist))){ gs <- lapply(1:length(netlist), function(x) autographr(netlist[[x]], ...) + @@ -111,19 +105,27 @@ autographs <- function(netlist, ...) { #' @importFrom ggraph create_layout #' @importFrom dplyr mutate select distinct left_join %>% #' @source http://blog.schochastics.net/post/animating-network-evolutions-with-gganimate/ +#' @examples +#' #ison_adolescents %>% +#' # mutate_ties(year = sample(1995:1998, 10, replace = TRUE)) %>% +#' # to_waves(attribute = "year") %>% +#' # autographd() +#' #ison_adolescents %>% +#' # mutate(shape = rep(c("circle", "square"), times = 4), +#' # color = rep(c("blue", "red"), times = 4), +#' # size = sample(4:16, 8, replace = TRUE)) %>% +#' # mutate_ties(year = sample(1995:1998, 10, replace = TRUE), +#' # e_color = sample(c("yellow", "green"), 10, replace = TRUE)) %>% +#' # to_waves(attribute = "year") %>% +#' # autographd(keep_isolates = FALSE, layout = "circle", node_shape = "shape", +#' # node_color = "color", node_size = "size", +#' # edge_color = "e_color") #' @export autographd <- function(tlist, keep_isolates = TRUE, layout = "stress", labels = TRUE, node_color = NULL, node_shape = NULL, node_size = NULL, edge_color = NULL) { # Todo: add (...) arguments passed on to `ggraph()`/`ggplot()`/`gganimate()` - if (!requireNamespace("gganimate", quietly = TRUE)) { - if(utils::askYesNo(msg = "The `gganimate` package is required. - Would you like to install `gganimate` from CRAN?")) { - utils::install.packages('gganimate') - } else { - stop("Please install `gganimate` from CRAN to animate plots.") - } - } + thisRequires("gganimate") x <- y <- name <- status <- frame <- NULL # Check if object is a list of lists if (!is.list(tlist[[1]])) { @@ -184,12 +186,36 @@ autographd <- function(tlist, keep_isolates = TRUE, layout = "stress", ggplot2::theme_void() } +.infer_layout <- function(g, layout){ + if(is.null(layout)){ + if (is_twomode(g)) layout <- "hierarchy" else + layout <- "stress" + } + layout +} + +.infer_nsize <- function(g, node_size){ + if (!is.null(node_size)) { + if (is.character(node_size)) { + out <- node_attribute(g, node_size) + } else if (is.numeric(node_size)) { + out <- node_size + } else { + out <- node_size(g) + } + if(all(out <= 1 & out >= 0)) out <- out*10 + } else { + out <- ifelse(network_nodes(g) <= 10, 5, (100 / network_nodes(g)) / 2) + } + out +} + #' @importFrom ggraph create_layout ggraph #' @importFrom igraph get.vertex.attribute #' @importFrom ggplot2 theme_void -.graph_layout <- function(g, layout, labels){ +.graph_layout <- function(g, layout, labels, ...){ name <- NULL - lo <- ggraph::create_layout(g, layout) + lo <- ggraph::create_layout(g, layout, ...) if ("graph" %in% names(attributes(lo))) { if (!setequal(names(as.data.frame(attr(lo, "graph"))), names(lo))) { for (n in setdiff(names(as.data.frame(attr(lo, "graph"))), names(lo))) { @@ -389,18 +415,9 @@ autographd <- function(tlist, keep_isolates = TRUE, layout = "stress", } .graph_nodes <- function(p, g, node_color, node_shape, node_size){ - if (!is.null(node_size)) { - if (is.character(node_size)) { - nsize <- node_attribute(g, node_size) - } else if (is.numeric(node_size)) { - nsize <- node_size - } else { - nsize <- node_size(g) - } - } else { - nsize <- ifelse(network_nodes(g) <= 10, 5, (100 / network_nodes(g)) / 2) - } - + + nsize <- .infer_nsize(g, node_size) + if (!is.null(node_shape)) { node_shape <- as.factor(node_attribute(g, node_shape)) node_shape <- c("circle","square","triangle")[node_shape] @@ -411,6 +428,7 @@ autographd <- function(tlist, keep_isolates = TRUE, layout = "stress", } else { node_shape <- "circle" } + if (is_twomode(g)) { if (!is.null(node_color)) { color_factor_node <- as.factor(node_attribute(g, node_color)) @@ -436,8 +454,7 @@ autographd <- function(tlist, keep_isolates = TRUE, layout = "stress", -1,1), guide = "none") } else { - p <- p + ggraph::geom_node_point(size = nsize, - shape = node_shape) + p <- p + ggraph::geom_node_point(size = nsize, shape = node_shape) } } p diff --git a/R/map_is.R b/R/map_is.R index bcd3443..7fd6ef6 100644 --- a/R/map_is.R +++ b/R/map_is.R @@ -265,12 +265,12 @@ is_complex <- function(.data) UseMethod("is_complex") #' @export is_complex.igraph <- function(.data) { - any(igraph::which_loop(.data)) + igraph::any_loop(.data) } #' @export is_complex.tbl_graph <- function(.data) { - any(igraph::which_loop(.data)) + igraph::any_loop(.data) } #' @export @@ -352,6 +352,95 @@ is_dynamic <- function(.data) { "time" %in% atts | "beg" %in% atts | "begin" %in% atts | "start" %in% atts } +# Features #### + +#' Marking networks based on their properties +#' +#' These functions implement logical tests for various network +#' properties. +#' @param .data An object of a `{manynet}`-consistent class: +#' \itemize{ +#' \item matrix (adjacency or incidence) from `{base}` R +#' \item edgelist, a data frame from `{base}` R or tibble from `{tibble}` +#' \item igraph, from the `{igraph}` package +#' \item network, from the `{network}` package +#' \item tbl_graph, from the `{tidygraph}` package +#' } +#' @return TRUE if the condition is met, or FALSE otherwise. +#' @family marks +#' @name is +NULL + +#' @describeIn is Tests whether network is weakly connected if +#' the network is undirected or strongly connected if directed. +#' To test weak connection on a directed network, +#' please see `to_undirected()`. +#' @importFrom igraph is.connected +#' @examples +#' is_connected(ison_southern_women) +#' @export +is_connected <- function(.data) { + igraph::is.connected(as_igraph(.data), + mode = ifelse(is_directed(.data), + "strong", "weak")) +} + +#' @describeIn is Tests whether there is a matching for a network +#' that covers every node in the network +#' @param mark A logical vector marking two types or modes. +#' By default "type". +#' @examples +#' is_perfect_matching(ison_southern_women) +#' @export +is_perfect_matching <- function(.data, mark = "type"){ + matches <- to_matching(.data, mark = mark) + network_ties(matches)*2 == network_nodes(matches) +} + +#' @describeIn is Tests whether there is a Eulerian path for a network +#' where that path passes through every tie exactly once +#' @importFrom igraph has_eulerian_path +#' @examples +#' is_eulerian(ison_brandes) +#' @export +is_eulerian <- function(.data){ + igraph::has_eulerian_path(as_igraph(.data)) +} + +#' @describeIn is Tests whether network is a directed acyclic graph +#' @importFrom igraph is_dag +#' @examples +#' is_acyclic(ison_algebra) +#' @export +is_acyclic <- function(.data){ + obj <- as_igraph(.data) + igraph::is_dag(obj) +} + +#' @describeIn is Tests whether network is aperiodic +#' @param max_path_length Maximum path length considered. +#' If negative, paths of all lengths are considered. +#' By default 4, to avoid potentially very long computation times. +#' @source https://stackoverflow.com/questions/55091438/r-igraph-find-all-cycles +#' @examples +#' is_aperiodic(ison_algebra) +#' @export +is_aperiodic <- function(.data, max_path_length = 4){ + g <- as_igraph(.data) + out <- NULL + for(v1 in igraph::V(g)) { + if(igraph::degree(g, v1, mode="in") == 0) {next} + goodNeighbors <- igraph::neighbors(g, v1, mode="out") + goodNeighbors <- goodNeighbors[goodNeighbors > v1] + out <- c(out, unlist(lapply(goodNeighbors, function(v2){ + vapply(igraph::all_simple_paths(g, v2, v1, mode="out", + cutoff = max_path_length), length, FUN.VALUE = numeric(1)) + }))) + } + thisRequires("minMSE") + minMSE::vector_gcd(out)==1 +} + # Helper functions infer_network_reciprocity <- function(.data, method = "default") { out <- igraph::reciprocity(as_igraph(.data), mode = method) diff --git a/R/map_layout_partition.R b/R/map_layout_partition.R new file mode 100644 index 0000000..e0b9013 --- /dev/null +++ b/R/map_layout_partition.R @@ -0,0 +1,225 @@ +#' Layout algorithms based on bi- or other partitions +#' +#' @description +#' These algorithms layout networks based on two or more partitions, +#' and are recommended for use with `autographr()` or `{ggraph}`. +#' Note that these layout algorithms use `{Rgraphviz}`, +#' a package that is only available on Bioconductor. +#' It will first need to be downloaded using `BiocManager::install("Rgraphviz")`. +#' +#' The "hierarchy" layout layers the first node set along the bottom, +#' and the second node set along the top, +#' sequenced and spaced as necessary to minimise edge overlap. +#' The "alluvial" layout is similar to "hierarchy", +#' but places successive layers horizontally rather than vertically. +#' The "railway" layout is similar to "hierarchy", +#' but nodes are aligned across the layers. +#' The "ladder" layout is similar to "railway", +#' but places successive layers horizontally rather than vertically. +#' The "concentric" layout places a "hierarchy" layout +#' around a circle, with successive layers appearing as concentric circles. +#' @name partition_layouts +#' @inheritParams transform +#' @param circular Should the layout be transformed into a radial representation. +#' Only possible for some layouts. Defaults to FALSE +#' @param times Maximum number of iterations, where appropriate +#' @param radius A vector of radii at which the concentric circles +#' should be located. +#' By default this is equal placement around an empty centre, +#' unless one (the core) is a single node, +#' in which case this node occupies the centre of the graph. +#' @param order.by An attribute label indicating the (decreasing) order +#' for the nodes around the circles. +#' By default ordering is given by a bipartite placement that reduces +#' the number of edge crossings. +#' @family mapping +#' @source +#' Diego Diez, Andrew P. Hutchins and Diego Miranda-Saavedra. 2014. +#' "Systematic identification of transcriptional regulatory modules from +#' protein-protein interaction networks". +#' _Nucleic Acids Research_, 42 (1) e6. +NULL + +#' @rdname partition_layouts +#' @export +layout_tbl_graph_hierarchy <- function(.data, + circular = FALSE, times = 1000){ + + thisRequiresBio("Rgraphviz") + prep <- as_matrix(.data, twomode = FALSE) + if(anyDuplicated(rownames(prep))){ + rownames(prep) <- seq_len(nrow(prep)) + colnames(prep) <- seq_len(ncol(prep)) + } + if(any(prep<0)) prep[prep<0] <- 0 + out <- as_graphAM(prep) + out <- suppressMessages(Rgraphviz::layoutGraph(out, layoutType = 'dot', + attrs = list(graph = list(rankdir = "BT")))) + nodeX <- .rescale(out@renderInfo@nodes$nodeX) + nodeY <- .rescale(out@renderInfo@nodes$nodeY) + # nodeY <- abs(nodeY - max(nodeY)) + .to_lo(cbind(nodeX, nodeY)) +} + +#' @rdname partition_layouts +#' @export +layout_tbl_graph_alluvial <- function(.data, + circular = FALSE, times = 1000){ + thisRequiresBio("Rgraphviz") + prep <- as_matrix(.data, twomode = FALSE) + if(anyDuplicated(rownames(prep))){ + rownames(prep) <- seq_len(nrow(prep)) + colnames(prep) <- seq_len(ncol(prep)) + } + if(any(prep<0)) prep[prep<0] <- 0 + out <- as_graphAM(prep) + out <- suppressMessages(Rgraphviz::layoutGraph(out, layoutType = 'dot', + attrs = list(graph = list(rankdir = "LR")))) + nodeX <- .rescale(out@renderInfo@nodes$nodeX) + nodeY <- .rescale(out@renderInfo@nodes$nodeY) + # nodeY <- abs(nodeY - max(nodeY)) + .to_lo(cbind(nodeX, nodeY)) +} + +#' @rdname partition_layouts +#' @export +layout_tbl_graph_railway <- function(.data, + circular = FALSE, times = 1000){ + res <- layout_tbl_graph_hierarchy(as_igraph(.data)) + res$x <- c(match(res[res[,2]==0,1], sort(res[res[,2]==0,1])), + match(res[res[,2]==1,1], sort(res[res[,2]==1,1]))) + res +} + +#' @rdname partition_layouts +#' @export +layout_tbl_graph_ladder <- function(.data, + circular = FALSE, times = 1000){ + res <- layout_tbl_graph_alluvial(as_igraph(.data)) + res$y <- c(match(res[res[,2]==1,1], sort(res[res[,2]==1,1])), + match(res[res[,2]==0,1], sort(res[res[,2]==0,1]))) + res +} + +#' @rdname partition_layouts +#' @export +layout_tbl_graph_concentric <- function(.data, membership = NULL, radius = NULL, + order.by = NULL, + circular = FALSE, times = 1000){ + if (is.null(membership)){ + if(is_twomode(.data)) + membership <- node_mode(.data) else + stop("Please pass the function a `membership` vector.") + } + if(is.null(names(membership)) & is_labelled(.data)) + names(membership) <- node_names(.data) + membership <- to_list(membership) + all_c <- unlist(membership, use.names = FALSE) + if (any(table(all_c) > 1)) + stop("Duplicated nodes in layers!") + if(is_labelled(.data)) + all_n <- node_names(.data) else + all_n <- 1:network_nodes(.data) + sel_other <- all_n[!all_n %in% all_c] + if (length(sel_other) > 0) + membership[[length(membership) + 1]] <- sel_other + if (is.null(radius)) { + radius <- seq(0, 1, 1/(length(membership))) + if (length(membership[[1]]) == 1) + radius <- radius[-length(radius)] else + radius <- radius[-1] + } + if (!is.null(order.by)){ + order.values <- lapply(order.by, + function(b) node_attribute(.data, b)) + } else { + for(k in 2:length(membership)){ + xnet <- as_matrix(to_multilevel(.data))[membership[[k-1]], + membership[[k]]] + lo <- layout_tbl_graph_hierarchy(as_igraph(xnet, twomode = TRUE)) + lo$names <- node_names(.data) + if(ncol(lo)==2) lo[,1] <- seq_len(lo) + order.values <- lapply(1:0, function(x) + if(ncol(lo)>=3) sort(lo[lo[,2]==x,])[,3] + else sort(lo[lo[,2]==x,1]) ) + } + # order.values <- getNNvec(.data, members) + } + res <- matrix(NA, nrow = length(all_n), ncol = 2) + for (k in seq_along(membership)) { + r <- radius[k] + l <- order.values[[k]] + if(is_labelled(.data)) + l <- match(l, node_names(.data)) + res[l, ] <- getCoordinates(l, r) + } + .to_lo(res) +} + +.rescale <- function(vector){ + (vector - min(vector)) / (max(vector) - min(vector)) +} + +.to_lo <- function(mat){ + res <- as.data.frame(mat) + names(res) <- c("x","y") + res +} + +to_list <- function(members){ + out <- lapply(sort(unique(members)), function(x){ + y <- which(members==x) + if(!is.null(names(y))) names(y) else y + }) + names(out) <- unique(members) + out +} + +#' @importFrom igraph degree +getNNvec <- function(.data, members){ + lapply(members, function(circle){ + diss <- 1 - stats::cor(to_multilevel(as_matrix(.data))[, circle]) + diag(diss) <- NA + if(is_labelled(.data)) + starts <- names(sort(igraph::degree(.data)[circle], decreasing = TRUE)[1]) + else starts <- paste0("V",1:network_nodes(.data))[sort(igraph::degree(.data)[circle], + decreasing = TRUE)[1]] + if(length(circle)>1) + starts <- c(starts, names(which.min(diss[starts,]))) + out <- starts + if(length(circle)>2){ + for(i in 1:(length(circle)-2)){ + diss <- diss[,!colnames(diss) %in% starts] + if(is.matrix(diss)){ + side <- names(which.min(apply(diss[starts,], 1, min, na.rm = TRUE))) + new <- names(which.min(diss[side,])) + } else { + side <- names(which.min(diss[starts])) + new <- setdiff(circle,out) + } + if(side == out[1]){ + out <- c(new, out) + starts <- c(new, starts[2]) + } else { + out <- c(out, new) + starts <- c(starts[1], new) + } + } + } + out + }) +} + +getCoordinates <- function(x, r){ + l <- length(x) + d <- 360/l + c1 <- seq(0, 360, d) + c1 <- c1[1:(length(c1) - 1)] + tmp <- t(vapply(c1, + function(cc) c(cos(cc * pi/180) * + r, sin(cc * + pi/180) * r), + FUN.VALUE = numeric(2))) + rownames(tmp) <- x + tmp +} diff --git a/R/map_palette.R b/R/map_palette.R deleted file mode 100644 index 9215f9a..0000000 --- a/R/map_palette.R +++ /dev/null @@ -1,6 +0,0 @@ -colorsafe_palette <- c("#1B9E77","#D95F02","#7570B3","#E7298A", - "#66A61E","#E6AB02","#A6761D","#666666") -# colorsafe_palette <- c('#000000','#d73027','#4575b4', -# '#f46d43','#74add1','#fee090','#e0f3f8', -# '#a50026','#313695', -# '#fdae61','#abd9e9') diff --git a/R/map_palettes.R b/R/map_palettes.R new file mode 100644 index 0000000..bd86bd6 --- /dev/null +++ b/R/map_palettes.R @@ -0,0 +1,100 @@ +# #' Complete list of palettes +# #' +# #' Use \code{\link{iheid_palette}} to construct palettes of desired length. +iheid_palettes <- list("IHEID" = c("IHEIDRed" = "#E20020", + "IHEIDBlack" = "#5c666f", + "IHEIDGrey" = "#6f7072"), + "Centres" = c("AHCD" = "#622550", + "CFFD" = "#0094D8", + "CIES" = "#268D2B", + "CTEI" = "#008F92", + "CGEN" = "#820C2B", + "CCDP" = "#3E2682", + "GLGC" = "#006564", + "GLHC" = "#A8086E", + "GLMC" = "#006EAA"), + "SDGs" = c("NoPoverty" = "#e5243b", + "ZeroHunger" = "#DDA63A", + "GoodHealth" = "#4C9F38", + "QualityEducation" = "#C5192D", + "GenderEquality" = "#FF3A21", + "CleanWater" = "#26BDE2", + "CleanEnergy" = "#FCC30B", + "EconomicGrowth" = "#A21942", + "Innovation" = "#FD6925", + "ReducedInequalities" = "#DD1367", + "SustainableCities" = "#FD9D24", + "ResponsibleConsumption" = "#BF8B2E", + "ClimateAction" = "#3F7E44", + "BelowWater" = "#0A97D9", + "OnLand" = "#56C02B", + "StrongInstitutions" = "#00689D", + "GoalPartnerships" = "#19486A")) + +# An IHEID palette generator + +# These are a few color palettes useful for members of the Geneva Graduate Institute. +# This function calls one of three official palettes in +# \code{\link{iheid_palette}}: for the Institute, for the Centres, and for the +# SDGs. + +# #' @param n Number of colors desired. If omitted, uses all colours. +# #' @param name Name of desired palette. Current choices are: +# #' \code{IHEID}, \code{Centres}, and \code{SDGs}. +# #' @param type Either "continuous" or "discrete". Use continuous if you want +# #' to automatically interpolate between colours. +# #' @importFrom graphics rect par image text +# #' @return A vector of colours. +# #' @source Adapted from +# \url{https://github.com/karthik/wesanderson/blob/master/R/colors.R} +# #' @keywords colors +# #' @examples +# \donttest{ +#iheid_palette("IHEID") +#iheid_palette("Centres") +#iheid_palette("SDGs") +# If you need more colours than normally found in a palette, you +# can use a continuous palette to interpolate between existing colours +#pal <- iheid_palette(21, name = "Centres", type = "continuous") +#image(volcano, col = pal) +# } +iheid_palette <- function(name, n, type = c("discrete", "continuous")) { + type <- match.arg(type) + pal <- iheid_palettes[[name]] + if (is.null(pal)) + stop("Palette not found.") + if (missing(n)) { + n <- length(pal) + } + if (type == "discrete" && n > length(pal)) { + stop("Number of requested colors greater than what palette can offer") + } + thisRequires("grDevices") + out <- switch(type, + continuous = grDevices::colorRampPalette(pal)(n), + discrete = pal[1:n] + ) + structure(out, class = "palette", name = name) +} + +print.palette <- function(x, ...) { + thisRequires("grDevices") + thisRequires("graphics") + n <- length(x) + old <- graphics::par(mar = c(0.5, 0.5, 0.5, 0.5)) + on.exit(graphics::par(old)) + graphics::image(1:n, 1, as.matrix(1:n), col = x, + ylab = "", xaxt = "n", yaxt = "n", bty = "n") + graphics::rect(0, 0.9, n + 1, 1.1, col = grDevices::rgb(1, 1, 1, 0.8), + border = NA) + graphics::text((n + 1) / 2, 1, labels = attr(x, "name"), + cex = 1, family = "serif") +} + +colorsafe_palette <- c("#1B9E77","#D95F02","#7570B3","#E7298A", + "#66A61E","#E6AB02","#A6761D","#666666") +# colorsafe_palette <- c('#000000','#d73027','#4575b4', +# '#f46d43','#74add1','#fee090','#e0f3f8', +# '#a50026','#313695', +# '#fdae61','#abd9e9') + diff --git a/R/map_plot.R b/R/map_plot.R new file mode 100644 index 0000000..cb4c385 --- /dev/null +++ b/R/map_plot.R @@ -0,0 +1,272 @@ +#' #' Plot agreements network +#' #' +#' #' @description Facilitates plotting of 'many' data. +#' #' @param dataset A dataset from one of the many packages +#' #' or a "consolidated" database. +#' #' @param actor An actor variable. +#' #' "stateID", by default. +#' #' @param treaty_type The type of treaties to be returned. +#' #' NULL, by default. +#' #' Other options are "bilateral" or "multilateral". +#' #' @param key An ID column to collapse by. +#' #' By default "manyID". +#' #' @param layout How do you want the plot to look like? +#' #' An `{ggraph}` layout algorithm. +#' #' If not declared, reasonable defaults are used. +#' #' @name plot_ +#' NULL +#' +#' #' @rdname plot_ +#' #' @importFrom dplyr %>% select mutate distinct rename +#' #' @return A network of agreements' relations. +#' #' @examples +#' #' \donttest{ +#' #' #agreements <- dplyr::filter(manyenviron::agreements$ECOLEX, +#' #' #Begin > "2000-01-01" & Begin < "2000-12-12") +#' #' #plot_agreements(agreements) +#' #'} +#' #' @export +#' plot_agreements <- function(dataset, treaty_type = NULL, key = "manyID", +#' layout = "circle") { +#' manyID <- treatyID <- name <- NULL +#' if (key == "manyID") { +#' out <- dplyr::select(dataset, manyID) %>% +#' dplyr::rename(key = manyID) %>% +#' dplyr::distinct() +#' } else if (key == "treatyID") { +#' out <- dplyr::select(dataset, treatyID) %>% +#' dplyr::rename(key == treatyID) %>% +#' dplyr::distinct() +#' } else stop("Please declare either 'manyID' or 'treatyID'.") +#' if (!is.null(treaty_type)) { +#' if (treaty_type == "bilateral") { +#' out <- out[grep("-", out$key),] +#' } +#' if (treaty_type == "multilateral") { +#' out <- out[grep("-", out$key, invert = TRUE),] +#' } +#' } +#' dplyr::mutate(out, +#' link = ifelse(grepl(":", key), sapply(strsplit(key, ":"), +#' "[", 2), "NA"), +#' key = gsub("\\:.*", "", key)) %>% +#' as_tidygraph() %>% +#' dplyr::filter(name != "NA") %>% +#' autographr(layout = layout) +#' } +#' +#' #' @rdname plot_ +#' #' @importFrom dplyr %>% select distinct all_of rename +#' #' @return A network of agreements' memberships. +#' #' @examples +#' #' \donttest{ +#' #' #memberships <- dplyr::filter(manyenviron::memberships$ECOLEX_MEM, +#' #' #Begin > "2000-01-01" & Begin < "2000-01-31") +#' #' #plot_memberships(memberships) +#' #'} +#' #' @export +#' plot_memberships <- function(dataset, actor = "stateID", treaty_type = NULL, +#' key = "manyID", layout = "bipartite") { +#' manyID <- treatyID <- name <- NULL +#' if (key == "manyID") { +#' out <- dplyr::select(dataset, manyID, dplyr::all_of(actor)) %>% +#' dplyr::rename(key = manyID) %>% +#' dplyr::distinct() +#' } else if (key == "treatyID") { +#' out <- dplyr::select(dataset, treatyID, dplyr::all_of(actor)) %>% +#' dplyr::rename(key == treatyID) %>% +#' dplyr::distinct() +#' } else stop("Please declare either 'manyID' or 'treatyID'.") +#' if (!is.null(treaty_type)) { +#' if (treaty_type == "bilateral") { +#' out <- out[grep("-", out$key),] +#' } +#' if (treaty_type == "multilateral") { +#' out <- out[grep("-", out$key, invert = TRUE),] +#' } +#' } +#' stats::na.omit(out) %>% +#' as_tidygraph() %>% +#' mutate(type = ifelse(grepl("[0-9][0-9][0-9][0-9][A-Za-z]", +#' name), TRUE, FALSE)) %>% +#' autographr(layout = layout) +#' } +#' +#' #' @rdname plot_ +#' #' @importFrom dplyr %>% select mutate distinct filter rename +#' #' @return A plot of agreements' lineages. +#' #' @examples +#' #' \donttest{ +#' #' #lineage <- dplyr::filter(manyenviron::agreements$HUGGO, +#' #' #Begin > "2000-01-01", Begin < "2001-12-31") +#' #' #plot_lineage(lineage) +#' #' } +#' #' @export +#' plot_lineage <- function(dataset, treaty_type = NULL, key = "manyID", +#' layout = "nicely") { +#' manyID <- treatyID <- name <- NULL +#' if (key == "manyID") { +#' out <- dplyr::select(dataset, manyID) %>% +#' dplyr::rename(key = manyID) %>% +#' dplyr::distinct() +#' } else if (key == "treatyID") { +#' out <- dplyr::select(dataset, treatyID) %>% +#' dplyr::rename(key == treatyID) %>% +#' dplyr::distinct() +#' } else stop("Please declare either 'manyID' or 'treatyID'.") +#' if (!is.null(treaty_type)) { +#' if (treaty_type == "bilateral") { +#' out <- out[grep("-", out$key),] +#' } +#' if (treaty_type == "multilateral") { +#' out <- out[grep("-", out$key, invert = TRUE),] +#' } +#' } +#' out %>% +#' dplyr::filter(grepl(":", key)) %>% +#' dplyr::mutate(key1 = gsub(".*\\:", "", key), +#' key = gsub("\\:.*", "", key)) %>% +#' dplyr::distinct() %>% +#' as_tidygraph() %>% +#' autographr(layout = "nicely") +#' } +#' +#' #' @rdname plot_ +#' #' @param date String date from the network snapshot. +#' #' Used by \code{{cshapes}} to plot the correct map. +#' #' By default, 2019-12-31. +#' #' Date can be between 1886-01-01 and 2019-12-31. +#' #' @param theme Theme you would like to use to plot the graph. +#' #' bey defalt, "light". +#' #' Available themes are "light", "dark", and "earth". +#' #' @details `plot_map()` creates a plot of the a unimodal geographical network +#' #' at a single point in time. +#' #' @importFrom dplyr mutate inner_join rename filter +#' #' @return A map of a country level geographical network. +#' #' @examples +#' #' \donttest{ +#' #' #memberships <- dplyr::filter(manyenviron::memberships$ECOLEX_MEM, +#' #' #Begin > "2000-01-01" & Begin < "2000-12-12") +#' #' #plot_map(memberships, actor = "stateID") + +#' #' #ggplot2::labs(title = "Bilateral International Environmental Treaties Signed in the year 2000", +#' #' #subtitle = "Ecolex data") +#' #'} +#' #' @export +#' plot_map <- function(dataset, actor = "stateID", treaty_type = NULL, +#' date = "2019-12-31", theme = "light") { +#' # check packages +#' thisRequires("cshapes") +#' thisRequires("manydata") +#' # Checks for correct input +#' weight <- .data <- NULL +#' # Step 1: get membership list +#' dataset <- manydata::call_treaties(dataset = dataset, actor = actor, +#' treaty_type = treaty_type) +#' # Step 2: set up empty matrix +#' actor <- unique(unlist(strsplit(dataset$Memberships, ", "))) +#' out <- matrix(0, nrow = length(actor), ncol = length(actor)) +#' rownames(out) <- actor +#' colnames(out) <- actor +#' # Step 3: fill matrix with values +#' for (k in colnames(out)) { +#' m <- data.frame(table(unlist(strsplit(grep(k, dataset$Memberships, +#' value = TRUE), ", ")))) +#' m <- m[!(m$Var1 %in% k),] +#' out[k, ] <- ifelse(names(out[k,]) %in% m$Var1 == TRUE, m$Freq/100, out[k,]) +#' } +#' out <- igraph::get.data.frame(igraph::graph.adjacency(out, weighted = TRUE)) +#' # Step 4 = get theme +#' if (theme == "dark") { +#' maptheme <- maptheme(palette = c("#FFFAFA", "#596673")) +#' countrycolor <- "#FFFAFA" +#' } +#' if (theme == "earth") { +#' maptheme <- maptheme(palette = c("#79B52F", "#4259FD")) +#' countrycolor <- "#79B52F" +#' } +#' if (theme == "light") { +#' maptheme <- maptheme(palette = c("#596673", "#FFFAFA")) +#' countrycolor <- "#596673" +#' } +#' # Step 5: import the historical shapefile data +#' cshapes <- cshapes::cshp(as.Date(date), useGW = FALSE) +#' coment <- vapply(countryregex[, 3], # add stateID abbreviations +#' function(x) grepl(x, cshapes$country_name, +#' ignore.case = TRUE, perl = TRUE) * 1, +#' FUN.VALUE = double(length(cshapes$country_name))) +#' colnames(coment) <- countryregex[, 1] +#' rownames(coment) <- cshapes$country_name +#' ab <- apply(coment, 1, function(x) paste(names(x[x == 1]), +#' collapse = "_")) +#' ab[ab == ""] <- NA +#' cshapes <- dplyr::mutate(cshapes, stateID = unname(ab)) +#' # Step 6: create edges with from/to lat/long +#' edges <- out %>% +#' dplyr::inner_join(cshapes, by = c("from" = "stateID")) %>% +#' dplyr::rename(x = .data$caplong, y = .data$caplat) %>% +#' dplyr::inner_join(cshapes, by = c("to" = "stateID")) %>% +#' dplyr::rename(xend = .data$caplong, yend = .data$caplat) +#' # Step 7: Create plotted network from computed edges +#' g <- as_tidygraph(edges) +#' # Step 8: Get the country shapes from the edges dataframe +#' country_shapes <- ggplot2::geom_sf(data = cshapes$geometry, +#' fill = countrycolor) +#' # Step 9: generate the point coordinates for capitals +#' cshapes_pos <- cshapes %>% +#' dplyr::filter(.data$stateID %in% node_names(g)) %>% +#' dplyr::rename(x = .data$caplong, y = .data$caplat) +#' # Reorder things according to nodes in plotted network g +#' cshapes_pos <- cshapes_pos[match(node_names(g), +#' cshapes_pos[["stateID"]]), ] +#' # Step 10: generate the layout +#' lay <- ggraph::create_layout(g, layout = cshapes_pos) +#' edges$circular <- rep(FALSE, nrow(edges)) +#' edges$edge.id <- rep(1, nrow(edges)) +#' # Step 11: plot +#' ggraph::ggraph(lay) + +#' country_shapes + +#' ggraph::geom_edge_arc(data = edges, ggplot2::aes(edge_width = weight), +#' strength = 0.33, alpha = 0.25) + +#' ggraph::scale_edge_width_continuous(range = c(0.5, 2), # scales edge widths +#' guide = "none") + +#' ggraph::geom_node_point(shape = 21, # draw nodes +#' fill = "white", color = "black", stroke = 0.5) + +#' ggraph::geom_node_text(ggplot2::aes(label = node_names(g)), +#' repel = TRUE, size = 3, color = "white", +#' fontface = "bold") + +#' maptheme +#' } +#' +#' # Helper function providing the network map function with a few map themes. +#' maptheme <- function(palette = c("#FFFAFA", "#596673")) { +#' oceancolor <- palette[2] +#' titlecolor <- ifelse(is_dark(palette[2]), "white", "black") +#' # Create map theme +#' maptheme <- ggplot2::theme(panel.grid = ggplot2::element_blank()) + +#' ggplot2::theme(axis.text = ggplot2::element_blank()) + +#' ggplot2::theme(axis.ticks = ggplot2::element_blank()) + +#' ggplot2::theme(axis.title = ggplot2::element_blank()) + +#' ggplot2::theme(legend.position = "bottom") + +#' ggplot2::theme(panel.grid = ggplot2::element_blank()) + +#' ggplot2::theme(panel.background = ggplot2::element_blank()) + +#' ggplot2::theme(plot.background = ggplot2::element_rect(fill = oceancolor)) + +#' ggplot2::theme(plot.title = ggplot2::element_text(color = titlecolor, +#' hjust = 0.1, vjust = 0.1), +#' plot.subtitle = ggplot2::element_text(color = titlecolor, +#' hjust = 0.065, +#' vjust = 0.1), +#' plot.caption = ggplot2::element_text(color = titlecolor, hjust = 0.96)) + +#' ggplot2::theme(plot.margin = ggplot2::unit(c(0, 0, 0.5, 0), "cm")) +#' # This function returns a map theme for ggplot +#' maptheme +#' } +#' +#' # Helper function to check whether a color is light or dark: +#' is_dark <- function(hex) { +#' # Google luma formula for details. +#' luma <- 0.33 * grDevices::col2rgb(hex)[[1]] + +#' 0.5 * grDevices::col2rgb(hex)[[2]] + +#' 0.16 * grDevices::col2rgb(hex)[[3]] +#' isdark <- ifelse(luma < 186, TRUE, FALSE) +#' isdark +#' } diff --git a/R/map_theme.R b/R/map_theme.R new file mode 100644 index 0000000..8f9754f --- /dev/null +++ b/R/map_theme.R @@ -0,0 +1,21 @@ +#' Theming ggraph +#' +#' @description +#' These functions enable graphs to be easily and quickly themed, +#' e.g. changing the default colour of the graph's vertices and edges. +#' Note that, unlike typical `{ggplot2}` theming, these functions +#' are passed the current plot with `%>%` rather than `+`. +#' For example, `autographr(ison_konigsberg) %>% theme_iheid()`. +#' @name themes +#' @param ggraph A ggraph object, e.g. created using `autographr()` +#' @return Themes the current ggraph to current IHEID guidelines. +NULL + +#' @rdname themes +#' @export +theme_iheid <- function(ggraph) { + ggraph[[2]][[1]]$geom$default_aes$colour <- iheid_palette("IHEID")["IHEIDBlack"] # Text colour + ggraph[[2]][[2]]$geom$default_aes$edge_colour <- iheid_palette("IHEID")["IHEIDGrey"] # Edge colour + ggraph[[2]][[3]]$geom$default_aes$colour <- iheid_palette("IHEID")["IHEIDRed"] # Vertex colour + ggraph +} diff --git a/README.md b/README.md index a6315f3..6125fbf 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,14 @@ [![Lifecycle: maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://lifecycle.r-lib.org/articles/stages.html#maturing) - - +![CRAN/METACRAN](https://img.shields.io/cran/v/manynet) ![GitHub release +(latest by +date)](https://img.shields.io/github/v/release/snlab-ch/manynet) ![GitHub Release Date](https://img.shields.io/github/release-date/snlab-ch/manynet) - - +[![Codecov test +coverage](https://codecov.io/gh/snlab-ch/manynet/branch/main/graph/badge.svg)](https://app.codecov.io/gh/snlab-ch/manynet?branch=main) +[![CodeFactor](https://www.codefactor.io/repository/github/snlab-ch/manynet/badge)](https://www.codefactor.io/repository/github/snlab-ch/manynet) @@ -32,8 +34,10 @@ undirected networks); if you have a different type of network, a different package is needed. Lastly, even packages with excellent graphical capabilities can make visualising networks slow and cumbersome by using poor defaults and many, incomprehensible options to change -them. `{manynet}` aims to help researchers with Making, Manipulating, -and Mapping networks. +them. + +*That’s why `{manynet}` aims to help researchers with Making, +Manipulating, and Mapping networks.* ## Making @@ -51,8 +55,8 @@ particular structure, and will always create the same format from the same inputs, e.g.: - `create_components()`, `create_core()`, `create_empty()`, - `create_filled()`, `create_lattice()`, `create_ring()`, - `create_star()`, `create_tree()` + `create_explicit()`, `create_filled()`, `create_lattice()`, + `create_ring()`, `create_star()`, `create_tree()` The `generate_*` group of functions generate networks from generative mechanisms that may include some random aspect, and so will return a @@ -114,12 +118,13 @@ reformat, transform, or split networks into networks with other properties, e.g.: - `to_acyclic()`, `to_anti()`, `to_blocks()`, `to_components()`, - `to_directed()`, `to_egos()`, `to_giant()`, `to_matching()`, - `to_mode1()`, `to_mode2()`, `to_multilevel()`, `to_named()`, - `to_onemode()`, `to_reciprocated()`, `to_redirected()`, - `to_simplex()`, `to_slices()`, `to_subgraph()`, `to_subgraphs()`, - `to_ties()`, `to_twomode()`, `to_undirected()`, `to_uniplex()`, - `to_unnamed()`, `to_unsigned()`, `to_unweighted()`, `to_waves()` + `to_directed()`, `to_egos()`, `to_eulerian()`, `to_giant()`, + `to_matching()`, `to_mode1()`, `to_mode2()`, `to_multilevel()`, + `to_named()`, `to_no_isolates()`, `to_onemode()`, `to_reciprocated()`, + `to_redirected()`, `to_simplex()`, `to_slices()`, `to_subgraph()`, + `to_subgraphs()`, `to_ties()`, `to_twomode()`, `to_undirected()`, + `to_uniplex()`, `to_unnamed()`, `to_unsigned()`, `to_unweighted()`, + `to_waves()` ### Reformatting @@ -154,10 +159,11 @@ function names wherever possible. `{manynet}`’s `*is_*()` functions offer fast logical tests of various network properties. These can be used to create new -- `is_bipartite()`, `is_complex()`, `is_directed()`, `is_dynamic()`, - `is_edgelist()`, `is_graph()`, `is_labelled()`, `is_longitudinal()`, - `is_manynet()`, `is_multiplex()`, `is_signed()`, `is_twomode()`, - `is_uniplex()`, `is_weighted()` +- `is_acyclic()`, `is_aperiodic()`, `is_bipartite()`, `is_complex()`, + `is_connected()`, `is_directed()`, `is_dynamic()`, `is_edgelist()`, + `is_eulerian()`, `is_graph()`, `is_labelled()`, `is_longitudinal()`, + `is_manynet()`, `is_multiplex()`, `is_perfect_matching()`, + `is_signed()`, `is_twomode()`, `is_uniplex()`, `is_weighted()` ## Mapping @@ -181,21 +187,16 @@ difference in results over `{igraph}`: -provide a common set of tools that can be used to import, export, -create, and manipulate network data in a wide variety of formats, and -obtain a good first visualisation quickly. This can be useful for -pedagogical purposes, initial description, or checking something part -way through the modelling process. Through the most comprehensive -network class-coercion available, users can access routines not -available in their chosen package or even in `{manynet}`. - -`{manynet}` provides a common set of tools and a standard syntax for -analysing many different types of networks. It offers a broad range of -functions to make, manipulate, map, measure, and model: - -- one-, two-, and sometimes three-mode networks -- undirected, directed, and sometimes complex networks -- unweighted, weighted, and sometimes signed networks + + + + + + + + + + ## Installation @@ -244,19 +245,47 @@ and then: - For latest development version: `remotes::install_github("snlab-ch/manynet@develop", build_vignettes = TRUE)` +### Tutorials + +This package includes a couple of tutorials to help new and experienced +users learn how they can conduct social network analysis using the +package. To access the tutorials, you will need to have the additional +package `{learnr}` installed: `install.packages("learnr")`. For more +details on the `{learnr}` package, see +[here](https://rstudio.github.io/learnr/). Then we suggest that you +check to see which vignettes are currently available: + +``` r +learnr::available_tutorials("manynet") +#> Available tutorials: +#> * manynet +#> - tutorial1 : "Data" +#> - tutorial2 : "Visualisation" +``` + +You can then choose to begin a tutorial using the following command: +e.g. `learnr::run_tutorial("tutorial2", "manynet")`. + ## Relationship to other packages -This package aims to provide an updated, and more comprehensive -replacement for `{intergraph}`. It also builds upon but makes some -different decisions to the excellent `{tidygraph}` package. It builds -upon `{igraph}` especially, as well as `{network}`, but works equally -well with basic edgelists and matrices. +This package stands on the shoulders of several incredible packages. + +In terms of the objects it works with, this package aims to provide an +updated, more comprehensive replacement for `{intergraph}`. As such it +works with objects in `{igraph}` and `{network}` formats, but also +equally well with base matrices and edgelists (data frames), and formats +from several other packages. -It works with and builds upon many popular network analytic packages, -such as `{igraph}` and `{network}`. +The user interface is inspired in some ways by Thomas Lin Pedersen’s +excellent `{tidygraph}` package, though makes some different decisions, +and uses the quickest `{igraph}` or `{network}` routines where +available. -`{manynet}` inherits core functionality from the `{migraph}` package. -For more analytic and modelling functions, please see `{migraph}`. +`{manynet}` has inherited most of its core functionality from its +maternal package, `{migraph}`. `{migraph}` continues to offer more +analytic and modelling functions that builds upon the architecture +provided by `{manynet}`. For more, please check out `{migraph}` +directly. ## Funding details diff --git a/data/ison_adolescents.rda b/data/ison_adolescents.rda index d372f99..86d07e6 100644 Binary files a/data/ison_adolescents.rda and b/data/ison_adolescents.rda differ diff --git a/data/ison_algebra.rda b/data/ison_algebra.rda index 1c118b5..d9fb714 100644 Binary files a/data/ison_algebra.rda and b/data/ison_algebra.rda differ diff --git a/data/ison_bb.rda b/data/ison_bb.rda deleted file mode 100644 index 2c9639f..0000000 Binary files a/data/ison_bb.rda and /dev/null differ diff --git a/data/ison_bm.rda b/data/ison_bm.rda deleted file mode 100644 index c371df8..0000000 Binary files a/data/ison_bm.rda and /dev/null differ diff --git a/data/ison_brandes.rda b/data/ison_brandes.rda index 843931d..0418357 100644 Binary files a/data/ison_brandes.rda and b/data/ison_brandes.rda differ diff --git a/data/ison_brandes2.rda b/data/ison_brandes2.rda deleted file mode 100644 index 6bb8600..0000000 Binary files a/data/ison_brandes2.rda and /dev/null differ diff --git a/data/ison_karateka.rda b/data/ison_karateka.rda index 0d3c197..b708c31 100644 Binary files a/data/ison_karateka.rda and b/data/ison_karateka.rda differ diff --git a/data/ison_konigsberg.rda b/data/ison_konigsberg.rda new file mode 100644 index 0000000..c5c2d3d Binary files /dev/null and b/data/ison_konigsberg.rda differ diff --git a/data/ison_laterals.rda b/data/ison_laterals.rda new file mode 100644 index 0000000..6894067 Binary files /dev/null and b/data/ison_laterals.rda differ diff --git a/data/ison_lotr.rda b/data/ison_lotr.rda index d57dd62..b62bec3 100644 Binary files a/data/ison_lotr.rda and b/data/ison_lotr.rda differ diff --git a/data/ison_mb.rda b/data/ison_mb.rda deleted file mode 100644 index 534c992..0000000 Binary files a/data/ison_mb.rda and /dev/null differ diff --git a/data/ison_mm.rda b/data/ison_mm.rda deleted file mode 100644 index 8b59377..0000000 Binary files a/data/ison_mm.rda and /dev/null differ diff --git a/data/ison_networkers.rda b/data/ison_networkers.rda index 0157c18..e5084ca 100644 Binary files a/data/ison_networkers.rda and b/data/ison_networkers.rda differ diff --git a/data/ison_southern_women.rda b/data/ison_southern_women.rda index b444024..6ef36b2 100644 Binary files a/data/ison_southern_women.rda and b/data/ison_southern_women.rda differ diff --git a/inst/tutorials/tutorial1/data.Rmd b/inst/tutorials/tutorial1/data.Rmd new file mode 100644 index 0000000..0e912ed --- /dev/null +++ b/inst/tutorials/tutorial1/data.Rmd @@ -0,0 +1,557 @@ +--- +title: "Data" +author: "by James Hollway" +output: + learnr::tutorial: + theme: journal +runtime: shiny_prerendered +--- + +```{r setup, include=FALSE} +library(learnr) +library(manynet) +knitr::opts_chunk$set(echo = FALSE) +``` + +# Introduction + +Network analysis is best with actual networks. +`{manynet}` offers several options for creating or generating, +importing or coercing networks into formats that you can use. +This tutorial is going to cover several ways to get data into the package: + +- using data from the `{manynet}` or other packages +- importing and using data from outside of R +- creating or generating networks using functions in the `{manynet}` package + +## Finding and using packaged data + +As many R packages do, `{manynet}` includes a number of datasets used for teaching and testing the functions contained in the package. +These are sometimes classical network datasets, +such as the [Southern Women](https://snlab-ch.github.io/manynet/reference/ison_southern_women.html) dataset or Zachary's [Karateka](https://snlab-ch.github.io/manynet/reference/ison_karateka.html) dataset, +and sometimes new data with neat themes, features, or attributes that make +them exemplar teaching or testing data. + +### Finding the data + +To see what data is in the package, +you can explore the documentation available on the website (see [here](https://snlab-ch.github.io/manynet/reference/index.html#data)) +or use a command in R to list the data available in the package. +The command, helpfully, is `data(package = "manynet")`. +Type this in to the box below to see what datasets are available in the package. +There are buttons to start over, receive any hints/solutions available, +as well as to run the code you have entered to discover its effects. +Try it out now! + +```{r pkgdata, exercise = TRUE} + +``` + +```{r pkgdata-hint} +data(package = "_____") +``` + +```{r pkgdata-solution} +data(package = "manynet") +``` + +### Calling the data + +Ok, so we can see that there are a number of very interesting datasets +available in this package. +How do we access and use this data? + +The easiest way to call the data is just to make sure that the package +is loaded using the command `library(manynet)`, +and then use the selected dataset as named above. +^[Alternatively, the data can be called directly out of the package like this: +`example_name <- manynet::ison_adolescents`, but since we think +you will probably want all of the other functions available in `{manynet}` +at your disposal, you may as well just load the package entirely.] +Let's try calling `ison_adolescents` by first loading the `{manynet}` 'library' +and then just typing `ison_adolescents` to see what happens. + +```{r calldata, exercise = TRUE} + +``` + +```{r calldata-hint} +library(______) +ison______ +``` + +```{r calldata-solution} +library(manynet) +ison_adolescents +``` + +### Formats + +All of the network data available in the package is in a special `tbl_graph` format, +from the `{tidygraph}` package, that makes it compatible, flexible, and transparent. +When you call one of these data objects, some information about the type of network it is, +how many nodes and ties it has, and the first few examples of nodes and ties is given. +^[You may have noticed when the package was first loaded that it mentioned that the `print_tbl_graph` method from that package was overwritten. +That's so that we can make some different choices about what and how networks +are described.] +Let's see whether we can make sense of the main features of this network? + +```{r tblgraph-nodes, echo = FALSE} +question("How many nodes does this network have?", + answer(8, + correct = TRUE), + answer(10, + message = "There are 10 ties."), + answer(1, + message = "There is one nodal variable ('name')."), + answer(2, + message = "There are two more nodes beyond what is listed."), + answer(6, + message = "There are six nodes/names shown, but the info underneath says there are 2 more."), + random_answer_order = TRUE, + allow_retry = TRUE +) +``` + +```{r tblgraph-ties, echo = FALSE} +question("How many ties does this network have?", + answer(4, + message = "There are four more ties beyond what is listed."), + answer(10, + correct = TRUE, + message = "There are 10 ties."), + answer(1, + message = "There is one network/graph."), + answer(2, + message = "There are two tie variables listing the nodes the tie is sent from and to."), + answer(6, + message = "There are six ties shown, but the info underneath says there are 4 more."), + random_answer_order = TRUE, + allow_retry = TRUE +) +``` + +```{r tblgraph-type, echo = FALSE} +question("From what is stated here, what kind of network is this?", + answer("Undirected", + correct = TRUE), + answer("Labelled", + correct = TRUE), + answer("Two-mode"), + answer("Complex"), + answer("Signed"), + answer("Weighted"), + random_answer_order = TRUE, + allow_retry = TRUE +) +``` + +We will see later how we can visualise, describe, and model this network +in a variety of ways. + +### Classes + +We can do the same with networks from other R packages too. +One challenge there though is that they may not be in the same `tbl_graph` format. +A commonly used package is `{network}`, which also includes a few example datasets. +Can you remember how to find out which data are available in this package, +and call the last one in the list? + +```{r netdata, exercise = TRUE} + +``` + +```{r netdata-hint-1} +# You may need to call the data out of this package directly, +# such as: +data(flo, package = "network") +``` + +```{r netdata-hint-2} +data(package = "_____") +library(_____) +data(_____) +_____ +``` + +```{r netdata-solution} +data(package = "network") +data(flo) +flo +``` + +This data uses quite a different class to what we encountered above. +It prints out the full adjacency list of the Florentine network, +but as a `network`-class object (i.e. from the `{network}` package). +This is no problem for `{manynet}` (or `{migraph}`), +since every included function works the same on any of the compatible classes, +but in case you would like to work with a network in a particular class, +or it needs to be in a particular format for further work (e.g. for use with `{ergm}`), +then `{manynet}` has you covered for that too. + +Coercing networks between different classes of objects uses the `as_*()` functions. +These functions will do their best to coerce data from the current class of the object +to the class named in the function. +Some classes have 'slots' or recognition for some kinds of information +that others don't. +For example, coercing a `tbl_graph` into an edgelist will sacrifice all the information +about nodal attributes. +Still, we aim for these functions to be as lossless as possible and welcome feedback +that highlights how these translations can be improved. +Let's see whether we can coerce our 'flo' network into a `tbl_graph` ('tidygraph') class object. + +```{r nettotbl, exercise = TRUE, exercise.setup = "netdata"} + +``` + +```{r nettotbl-hint-1} +_____ <- as_t_____(_____) +``` + +```{r nettotbl-hint-2} +flo <- as_tidygraph(_____) +``` + +```{r nettotbl-solution} +flo <- as_tidygraph(flo) +``` + +```{r nettotblquest, echo = FALSE} +question("What are there 16 of in this network?", + answer("Nodes", + correct = TRUE), + answer("Ties"), + answer("Reciprocated ties"), + answer("Loops"), + answer("Components"), + random_answer_order = TRUE, + allow_retry = TRUE +) +``` + +Other packages that include network data include +David Schoch's eponymous [`{networkdata}`](http://networkdata.schochastics.net/) package. +The data in this package are `{igraph}`-class objects. +Can you coerce one of the datasets in this package +into a tidygraph format? Into a network format? +Into a matrix? Into an edgelist? + +## Finding and importing external data + +### Finding data + +Researchers will regularly find themselves needing to import and work +with network data from outside of R though. +There are a great number of networks datasets and data resources available online. +^[Here we keep just a necessarily partial list, +but we are happy to update it whenever additional datasets are suggested.] +See for example: + +- [UCINET data](https://sites.google.com/site/ucinetsoftware/datasets?authuser=0) +- [Pajek data](http://vlado.fmf.uni-lj.si/pub/networks/data/) +- [GML datasets](http://www-personal.umich.edu/~mejn/netdata/) +- [UCIrvine Network Data Repository](http://networkdata.ics.uci.edu/) +- [KONECT project](http://konect.cc/) +- [SNAP Stanford Large Network Dataset Collection](http://snap.stanford.edu/data/) + +Yet these resources contain data in a range of different formats, +some that are specifically made to work with certain software, +others that rely on open standards, +and yet others that keep data in a very standard edgelist (and perhaps nodelist) format +in .csv files or similar. +Fortunately, `{manynet}` has functions to help with importing data from such formats too. + +### Importing edgelists + +One format most users are long familiar with is Excel. +In Excel, users are typically collecting network data as edgelists, nodelists, or both. +Recall that edgelists tabulate senders/from and receivers/to of each tie in the first two columns and any other edge- or tie-related attributes as additional columns. +There may optionally also be a nodelist that tabulates +Edgelists are typically the main object to be imported, +and we can import them from an Excel file or a `.csv` file.^[Note that if you import from a .csv file, please specify whether the separation value should be commas (`sv = "comma"`) or semi-colons (`sv = "semi-colon"`). The function expects comma separated values by default.] +For the sake of this exercise, we'll import some data, `adols.csv`, that I've pre-saved within the package in the `data/` folder of this tutorial. +Try the following code chunk. + +```{r importedges, exercise = TRUE} +adolties <- read_edgelist("data/adols.csv") +flonodes <- read_edgelist("data/flonode.csv") +``` + +If you do not specify a particular file name, +a helpful popup will open that assists you with locating and importing a file +from your operating system. +Importing a nodelist of nodal attributes operates very similarly. + +### Exporting edgelists + +In some cases, users will be faced with having to collect data themselves, +or wish to first manipulate the data in Excel before importing it, +but may be uncertain about the expected format of an edgelist. +Here it may be useful to try exporting one of the built-in datasets +in `{manynet}` to see how complete network data looks. +If this is potentially complex, +calling `write_edgelist()` without any arguments will export a test +file with a barebones structure that you can overwrite with your own data. + +```{r exportdata, exercise=TRUE} + +``` + +```{r exportdata-hint} +write______(ison_marvel_relationships, "_____/marvedges.xlsx") +write______(ison_marvel_relationships, "_____/marvnodes.xlsx") +``` + +```{r exportdata-solution} +write_edgelist(ison_marvel_relationships, "data/marvedges.xlsx") +write_nodelist(ison_marvel_relationships, "data/marvnodes.xlsx") +``` + +### Importing other formats + +There are other functions here too that help import from or export to +common external network data formats. +Here are some examples: + +- `read_pajek()` and `write_pajek()` for importing and exporting .net or .paj files +- `read_ucinet()` and `write_ucinet()` for importing and exporting .##h files (.##d files are automatically imported alongside them) + +For more information on any of these functions, you can also ask for help by typing `?read_pajek` in the console. +Whereas `read_edgelist()` and `read_nodelist()` will import into a tibble/data frame class, +`read_pajek()` and `read_ucinet()` will import the network into a tidygraph format (see above). +Of course, any network data that is imported can quite easily be coerced into any other compatible class. +Let's say we want to import the adolescents edgelist back in, but we want it in an igraph format. +There are three ways you might do this: + +```{r readcoerce, exercise = TRUE} +# 1. Separate steps +adols <- read_edgelist("data/adols.csv") +adolsigraph1 <- as_igraph(adols) +adolsigraph1 +# 2. Nested steps +adolsigraph2 <- as_igraph(read_edgelist("data/adols.csv")) +adolsigraph2 +# 3. Chained steps +adolsigraph3 <- read_edgelist("data/adols.csv") %>% as_igraph() +adolsigraph3 +``` + +How does it compare to the original? + +## Working with network data + +### Reformatting network data + +As mentioned above, `{manynet}` attempts to retain as much information as possible when converting objects between different classes. +The presumption is that users should explicitly decide to reduce or simplify their data. +`{manynet}` includes functions for reformatting, transforming (or removing) certain properties of network objects. +Here will introduce a few functions used for 'reformatting' networks. +We call functions 'reformatting functions' if they change the type but not the order (number of nodes) in the network. +A good example is `to_undirected()`. +The astute among you may have noticed that when we imported the adolescents network, +it returned a _directed_ network instead of the original _undirected_ network. +This was a consequence of a heuristic used during the import, +but gives us a good occasion to try out `to_undirected()`. +Reimport the `data/adols.csv` file, make it an igraph-class object, and then make it undirected. + +```{r adolsundir, exercise = TRUE} + +``` + +```{r adolsundir-solution} +read_edgelist("data/adols.csv") %>% as_igraph() %>% to_undirected() +``` + +Try this out with other compatible classes of objects, and reformatting other aspects of the network. +For example: + +- `to_unnamed()` removes/anonymises all vertex/node labels +- `to_named()` adds some random (U.S.) childrens' names, which can be useful for identifying particular nodes +- `to_undirected()` replaces directed ties with an undirected tie (if an arc in either direction is present) +- `to_redirected()` replaces undirected ties with directed ties (arcs) or, if already directed, swaps arcs' direction +- `to_unweighted()` binarises or dichotomises a network around a particular threshold (by default `1`) +- `to_unsigned()` returns just the "positive" or "negative" ties from a signed network, respectively +- `to_uniplex()` reduces a multigraph or multiplex network to one with a single set of edges or ties +- `to_simplex()` removes all loops or self-ties from a complex network + +### Transforming network data + +These functions are similar to the reformatting functions, and are also named `to_*()`, +but their operation always changes the order (number of nodes) in the network. +Good examples of this are `to_mode1()` and `to_mode2()` for transforming a two-mode network +into one of its one-mode projections. +`to_mode1()` will transform (project) the network to a one-mode network of shared ties among its first set of nodes, +while `to_mode2()` will project the original network to a network of shared ties among its second set of nodes. +For more information on projection, +see for example Knoke et al. (2021). +Let's try this out on a classic two-mode network, `ison_southern_women`. +Assign and name the transformed networks something sensible using e.g. +`women <- to_mode...` so that we can continue working with this data afterwards. +To assign and immediately print the result, wrap the line in parentheses. + +```{r southproj, exercise = TRUE} + +``` + +```{r southproj-solution} +ison_southern_women +(women <- to_mode1(ison_southern_women)) +(events <- to_mode2(ison_southern_women)) +``` + +```{r namemode1} +question("The first mode consists of...", + answer("women named Evelyn, Laura, Theresa, etc", + correct = TRUE), + answer("events called E1, E2, E3, etc"), + answer("southern cities named Dunedin, Invercargill, Bluff, etc"), + answer("events called Christmas Ball, End-of-year, Mardi Gras, etc"), + answer("women named Gertrude, Sally, Agnes, etc"), + random_answer_order = TRUE, + allow_retry = TRUE +) +``` + +### Grabbing key details from network data + +We can ask other questions of this data too. +`{manynet}` (and `{migraph}`) use a simple function naming convention so that +you always know to what it relates. + +- `network_*()` functions usually return one value for the network or graph, +whether that be a string like `Evelyn`, logical value like `TRUE`, or some number like `3` or `-0.003`^[There are a few exceptions to this in the `{manynet}` package, +or when attributes of the network are listed (see below).] +- `node_*()` functions always return a vector of values for the network +as long as the number of nodes or vertices in the network (of any mode) +- `tie_*()` functions always return a vector of values for the network +as long as the number of ties or edges in the network (of any sign or type) + +To find out how many nodes are in the network, use `network_nodes()`. +To find out how many nodes are in each mode, use `network_dims()`. +To find out the names of those nodes, use `node_names()`. +Use such functions to find out: + +a) how many nodes are in the `ison_southern_women` network +b) how many nodes are in each mode +b) how many ties are in the network +d) what nodal attributes there are in the network +c) what the names of the nodes are + +```{r properties, exercise = TRUE} + +``` + +```{r properties-solution} +network_nodes(ison_southern_women) +network_dims(ison_southern_women) +network_ties(ison_southern_women) +network_node_attributes(ison_southern_women) +node_names(ison_southern_women) +``` + +Now use these functions on the two projections you have created +to find out a) how many nodes there are in each of these networks, +b) what the names of the nodes are, +and c) what tie attributes there are in the networks. + +```{r projprop, exercise = TRUE, exercise.setup = "southproj"} + +``` + +```{r projprop-solution} +network_nodes(women) +node_names(women) +network_tie_attributes(women) +network_nodes(events) +node_names(events) +network_tie_attributes(events) +``` + +So we can see that the `to_mode*()` functions have created a network of only one of the modes in the network. +The ties in these projected networks, +representing shared connections to nodes of the other mode, are weighted. +This shows up when listing the network's tie attributes, +or could be retrieved using `tie_weights()`, +but can also be checked with the simple logical check `is_weighted()`. + +There are a bunch of logical checks for many common properties or features of networks. +For example, one can check whether a network `is_twomode()`, `is_directed()`, or `is_labelled()`. +Remember, all these `to_*()` and `is_*()` functions work on any compatible class; +the `to_*()` functions will also attempt to return that same class of object, +making it even easier to manipulate networks into shape for analysis. + +Retrieve the tie weights from your women projection. +Find the average (mean) of this vector of tie weights, +and the average (mean) tie weight overall. + +```{r womenweights, exercise = TRUE} + +``` + +```{r womenweights-hint-1} +tie_weights(_____) +``` + +```{r womenweights-hint-2} +mean(tie_weights(_____)) +``` + +```{r womenweights-hint-3} +mean(as_matrix(_____)) +``` + +```{r womenweights-solution} +tie_weights(women) +mean(tie_weights(women)) +mean(as_matrix(women)) +``` + +```{r womenweightsq} +question("2.438849 is...", + answer("the average frequency of events shared by women who shared any events.", + correct = TRUE), + answer("the average frequency of events shared by women."), + answer("how many shared events there are in original two-mode network."), + answer("how many women there are in the projected network."), + answer("how many shared events there are in the projected network."), + random_answer_order = TRUE, + allow_retry = TRUE +) +``` + +Ok, so now we know that projection transforms an (unweighted) two-mode network +into a weighted one-mode network and what these weights represent. +Note though that counting the frequency of shared ties to nodes in the other mode +is just one (albeit the default) option for how ties in the projection are weighted. +Other options included in `{manynet}` include the Jaccard index, Rand simple matching coefficient, Pearson coefficient, and Yule's Q. +These may be of interest if, for example, overlap should be weighted by participation. + +Other transforming functions include: + +- `to_giant()` identifies and returns only the main component of a network. +- `to_no_isolates()` identifies and returns a network including only nodes with at least one tie. +- `to_subgraph()` returns only a subgraph of the network based on e.g. some nodal attribute. +- `to_ties()` returns a network where the ties in the original network become the nodes, +and the ties are shared adjacencies to nodes. +- `to_matching()` returns a network in which each node is only tied to one of its previously existing ties such that the network's cardinality is maximised. + +### Adding data + +If you import one or more edgelists and nodelists, +it can be useful to bind these together in an igraph, tidygraph, or network class object. + +Adding nodal attributes to a given network is relatively straightforward. +`{manynet}` offers a more `{igraph}`-like syntax, e.g. `add_node_attribute()`, +as well as a more `{dplyr}`-like syntax, e.g. `mutate()`, +for those already familiar with these tools in R: + +```{r mutate, exercise = TRUE} +ison_adolescents %>% + mutate(color = "red", + degree = 1:8) %>% + mutate_ties(weight = 1:10) +``` + +Note that to use `{dplyr}`-like functions like +`mutate()`, `rename()`, `filter()`, `select()`, or `join()` on network ties, +you will need to append the function name with `_ties`. diff --git a/inst/tutorials/tutorial1/data.html b/inst/tutorials/tutorial1/data.html new file mode 100644 index 0000000..960ac53 --- /dev/null +++ b/inst/tutorials/tutorial1/data.html @@ -0,0 +1,1581 @@ + + + + + + + + + + + + + + + + + +Data + + + + + + + + + + + + + + + + + + + + + +Skip to Tutorial Content + + + +
+
+ +
+ +
+

Introduction

+

Network analysis is best with actual networks. {manynet} +offers several options for creating or generating, importing or coercing +networks into formats that you can use. This tutorial is going to cover +several ways to get data into the package:

+
    +
  • using data from the {manynet} or other packages
  • +
  • importing and using data from outside of R
  • +
  • creating or generating networks using functions in the +{manynet} package
  • +
+
+

Finding and using packaged data

+

As many R packages do, {manynet} includes a number of +datasets used for teaching and testing the functions contained in the +package. These are sometimes classical network datasets, such as the Southern +Women dataset or Zachary’s Karateka +dataset, and sometimes new data with neat themes, features, or +attributes that make them exemplar teaching or testing data.

+
+

Finding the data

+

To see what data is in the package, you can explore the documentation +available on the website (see here) +or use a command in R to list the data available in the package. The +command, helpfully, is data(package = "manynet"). Type this +in to the box below to see what datasets are available in the package. +There are buttons to start over, receive any hints/solutions available, +as well as to run the code you have entered to discover its effects. Try +it out now!

+
+ +
+
+
data(package = "_____")
+
+
+
data(package = "manynet")
+
+
+
+

Calling the data

+

Ok, so we can see that there are a number of very interesting +datasets available in this package. How do we access and use this +data?

+

The easiest way to call the data is just to make sure that the +package is loaded using the command library(manynet), and +then use the selected dataset as named above. 1 Let’s try +calling ison_adolescents by first loading the +{manynet} ‘library’ and then just typing +ison_adolescents to see what happens.

+
+ +
+
+
library(______)
+ison______
+
+
+
library(manynet)
+ison_adolescents
+
+
+
+
+
    +
  1. Alternatively, the data can be called directly +out of the package like this: +example_name <- manynet::ison_adolescents, but since we +think you will probably want all of the other functions available in +{manynet} at your disposal, you may as well just load the +package entirely.↩︎

  2. +
+
+
+

Formats

+

All of the network data available in the package is in a special +tbl_graph format, from the {tidygraph} +package, that makes it compatible, flexible, and transparent. When you +call one of these data objects, some information about the type of +network it is, how many nodes and ties it has, and the first few +examples of nodes and ties is given. 2 Let’s see +whether we can make sense of the main features of this network?

+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+

We will see later how we can visualise, describe, and model this +network in a variety of ways.

+
+
+
+
    +
  1. You may have noticed when the package was first +loaded that it mentioned that the print_tbl_graph method +from that package was overwritten. That’s so that we can make some +different choices about what and how networks are described.↩︎

  2. +
+
+
+

Classes

+

We can do the same with networks from other R packages too. One +challenge there though is that they may not be in the same +tbl_graph format. A commonly used package is +{network}, which also includes a few example datasets. Can +you remember how to find out which data are available in this package, +and call the last one in the list?

+
+ +
+
+
# You may need to call the data out of this package directly,
+# such as:
+data(flo, package = "network")
+
+
+
data(package = "_____")
+library(_____)
+data(_____)
+_____
+
+
+
data(package = "network")
+data(flo)
+flo
+
+

This data uses quite a different class to what we encountered above. +It prints out the full adjacency list of the Florentine network, but as +a network-class object (i.e. from the +{network} package). This is no problem for +{manynet} (or {migraph}), since every included +function works the same on any of the compatible classes, but in case +you would like to work with a network in a particular class, or it needs +to be in a particular format for further work (e.g. for use with +{ergm}), then {manynet} has you covered for +that too.

+

Coercing networks between different classes of objects uses the +as_*() functions. These functions will do their best to +coerce data from the current class of the object to the class named in +the function. Some classes have ‘slots’ or recognition for some kinds of +information that others don’t. For example, coercing a +tbl_graph into an edgelist will sacrifice all the +information about nodal attributes. Still, we aim for these functions to +be as lossless as possible and welcome feedback that highlights how +these translations can be improved. Let’s see whether we can coerce our +‘flo’ network into a tbl_graph (‘tidygraph’) class +object.

+
+ +
+
+
_____ <- as_t_____(_____)
+
+
+
flo <- as_tidygraph(_____)
+
+
+
flo <- as_tidygraph(flo)
+
+
+
+
+
+
+ +
+
+

Other packages that include network data include David Schoch’s +eponymous {networkdata} +package. The data in this package are {igraph}-class +objects. Can you coerce one of the datasets in this package into a +tidygraph format? Into a network format? Into a matrix? Into an +edgelist?

+
+
+
+

Finding and importing external data

+
+

Finding data

+

Researchers will regularly find themselves needing to import and work +with network data from outside of R though. There are a great number of +networks datasets and data resources available online. 3 See for example:

+ +

Yet these resources contain data in a range of different formats, +some that are specifically made to work with certain software, others +that rely on open standards, and yet others that keep data in a very +standard edgelist (and perhaps nodelist) format in .csv files or +similar. Fortunately, {manynet} has functions to help with +importing data from such formats too.

+
+
+
+
    +
  1. Here we keep just a necessarily partial list, +but we are happy to update it whenever additional datasets are +suggested.↩︎

  2. +
+
+
+

Importing edgelists

+

One format most users are long familiar with is Excel. In Excel, +users are typically collecting network data as edgelists, nodelists, or +both. Recall that edgelists tabulate senders/from and receivers/to of +each tie in the first two columns and any other edge- or tie-related +attributes as additional columns. There may optionally also be a +nodelist that tabulates Edgelists are typically the main object to be +imported, and we can import them from an Excel file or a +.csv file.4 For the sake of this exercise, +we’ll import some data, adols.csv, that I’ve pre-saved +within the package in the data/ folder of this tutorial. +Try the following code chunk.

+
+
adolties <- read_edgelist("data/adols.csv")
+flonodes <- read_edgelist("data/flonode.csv")
+ +
+

If you do not specify a particular file name, a helpful popup will +open that assists you with locating and importing a file from your +operating system. Importing a nodelist of nodal attributes operates very +similarly.

+
+
+
+
    +
  1. Note that if you import from a .csv file, please +specify whether the separation value should be commas +(sv = "comma") or semi-colons +(sv = "semi-colon"). The function expects comma separated +values by default.↩︎

  2. +
+
+
+

Exporting edgelists

+

In some cases, users will be faced with having to collect data +themselves, or wish to first manipulate the data in Excel before +importing it, but may be uncertain about the expected format of an +edgelist. Here it may be useful to try exporting one of the built-in +datasets in {manynet} to see how complete network data +looks. If this is potentially complex, calling +write_edgelist() without any arguments will export a test +file with a barebones structure that you can overwrite with your own +data.

+
+ +
+
+
write______(ison_marvel_relationships, "_____/marvedges.xlsx")
+write______(ison_marvel_relationships, "_____/marvnodes.xlsx")
+
+
+
write_edgelist(ison_marvel_relationships, "data/marvedges.xlsx")
+write_nodelist(ison_marvel_relationships, "data/marvnodes.xlsx")
+
+
+
+

Importing other formats

+

There are other functions here too that help import from or export to +common external network data formats. Here are some examples:

+
    +
  • read_pajek() and write_pajek() for +importing and exporting .net or .paj files
  • +
  • read_ucinet() and write_ucinet() for +importing and exporting .##h files (.##d files are automatically +imported alongside them)
  • +
+

For more information on any of these functions, you can also ask for +help by typing ?read_pajek in the console. Whereas +read_edgelist() and read_nodelist() will +import into a tibble/data frame class, read_pajek() and +read_ucinet() will import the network into a tidygraph +format (see above). Of course, any network data that is imported can +quite easily be coerced into any other compatible class. Let’s say we +want to import the adolescents edgelist back in, but we want it in an +igraph format. There are three ways you might do this:

+
+
# 1. Separate steps
+adols <- read_edgelist("data/adols.csv")
+adolsigraph1 <- as_igraph(adols)
+adolsigraph1
+# 2. Nested steps
+adolsigraph2 <- as_igraph(read_edgelist("data/adols.csv"))
+adolsigraph2
+# 3. Chained steps
+adolsigraph3 <- read_edgelist("data/adols.csv") %>% as_igraph()
+adolsigraph3
+ +
+

How does it compare to the original?

+
+
+
+

Working with network data

+
+

Reformatting network data

+

As mentioned above, {manynet} attempts to retain as much +information as possible when converting objects between different +classes. The presumption is that users should explicitly decide to +reduce or simplify their data. {manynet} includes functions +for reformatting, transforming (or removing) certain properties of +network objects. Here will introduce a few functions used for +‘reformatting’ networks. We call functions ‘reformatting functions’ if +they change the type but not the order (number of nodes) in the network. +A good example is to_undirected(). The astute among you may +have noticed that when we imported the adolescents network, it returned +a directed network instead of the original undirected +network. This was a consequence of a heuristic used during the import, +but gives us a good occasion to try out to_undirected(). +Reimport the data/adols.csv file, make it an igraph-class +object, and then make it undirected.

+
+ +
+
+
read_edgelist("data/adols.csv") %>% as_igraph() %>% to_undirected()
+
+

Try this out with other compatible classes of objects, and +reformatting other aspects of the network. For example:

+
    +
  • to_unnamed() removes/anonymises all vertex/node +labels
  • +
  • to_named() adds some random (U.S.) childrens’ names, +which can be useful for identifying particular nodes
  • +
  • to_undirected() replaces directed ties with an +undirected tie (if an arc in either direction is present)
  • +
  • to_redirected() replaces undirected ties with directed +ties (arcs) or, if already directed, swaps arcs’ direction
  • +
  • to_unweighted() binarises or dichotomises a network +around a particular threshold (by default 1)
  • +
  • to_unsigned() returns just the “positive” or “negative” +ties from a signed network, respectively
  • +
  • to_uniplex() reduces a multigraph or multiplex network +to one with a single set of edges or ties
  • +
  • to_simplex() removes all loops or self-ties from a +complex network
  • +
+
+
+

Transforming network data

+

These functions are similar to the reformatting functions, and are +also named to_*(), but their operation always changes the +order (number of nodes) in the network. Good examples of this are +to_mode1() and to_mode2() for transforming a +two-mode network into one of its one-mode projections. +to_mode1() will transform (project) the network to a +one-mode network of shared ties among its first set of nodes, while +to_mode2() will project the original network to a network +of shared ties among its second set of nodes. For more information on +projection, see for example Knoke et al. (2021). Let’s try this out on a +classic two-mode network, ison_southern_women. Assign and +name the transformed networks something sensible using e.g. +women <- to_mode... so that we can continue working with +this data afterwards. To assign and immediately print the result, wrap +the line in parentheses.

+
+ +
+
+
ison_southern_women
+(women <- to_mode1(ison_southern_women))
+(events <- to_mode2(ison_southern_women))
+
+
+
+
+
+
+ +
+
+
+
+

Grabbing key details from network data

+

We can ask other questions of this data too. {manynet} +(and {migraph}) use a simple function naming convention so +that you always know to what it relates.

+
    +
  • network_*() functions usually return one value for the +network or graph, whether that be a string like Evelyn, +logical value like TRUE, or some number like 3 +or -0.0035
  • +
  • node_*() functions always return a vector of values for +the network as long as the number of nodes or vertices in the network +(of any mode)
  • +
  • tie_*() functions always return a vector of values for +the network as long as the number of ties or edges in the network (of +any sign or type)
  • +
+

To find out how many nodes are in the network, use +network_nodes(). To find out how many nodes are in each +mode, use network_dims(). To find out the names of those +nodes, use node_names(). Use such functions to find +out:

+
    +
  1. how many nodes are in the ison_southern_women +network
  2. +
  3. how many nodes are in each mode
  4. +
  5. how many ties are in the network
  6. +
  7. what nodal attributes there are in the network
  8. +
  9. what the names of the nodes are
  10. +
+
+ +
+
+
network_nodes(ison_southern_women)
+network_dims(ison_southern_women)
+network_ties(ison_southern_women)
+network_node_attributes(ison_southern_women)
+node_names(ison_southern_women)
+
+

Now use these functions on the two projections you have created to +find out a) how many nodes there are in each of these networks, b) what +the names of the nodes are, and c) what tie attributes there are in the +networks.

+
+ +
+
+
network_nodes(women)
+node_names(women)
+network_tie_attributes(women)
+network_nodes(events)
+node_names(events)
+network_tie_attributes(events)
+
+

So we can see that the to_mode*() functions have created +a network of only one of the modes in the network. The ties in these +projected networks, representing shared connections to nodes of the +other mode, are weighted. This shows up when listing the network’s tie +attributes, or could be retrieved using tie_weights(), but +can also be checked with the simple logical check +is_weighted().

+

There are a bunch of logical checks for many common properties or +features of networks. For example, one can check whether a network +is_twomode(), is_directed(), or +is_labelled(). Remember, all these to_*() and +is_*() functions work on any compatible class; the +to_*() functions will also attempt to return that same +class of object, making it even easier to manipulate networks into shape +for analysis.

+

Retrieve the tie weights from your women projection. Find the average +(mean) of this vector of tie weights, and the average (mean) tie weight +overall.

+
+ +
+
+
tie_weights(_____)
+
+
+
mean(tie_weights(_____))
+
+
+
mean(as_matrix(_____))
+
+
+
tie_weights(women)
+mean(tie_weights(women))
+mean(as_matrix(women))
+
+
+
+
+
+
+ +
+
+

Ok, so now we know that projection transforms an (unweighted) +two-mode network into a weighted one-mode network and what these weights +represent. Note though that counting the frequency of shared ties to +nodes in the other mode is just one (albeit the default) option for how +ties in the projection are weighted. Other options included in +{manynet} include the Jaccard index, Rand simple matching +coefficient, Pearson coefficient, and Yule’s Q. These may be of interest +if, for example, overlap should be weighted by participation.

+

Other transforming functions include:

+
    +
  • to_giant() identifies and returns only the main +component of a network.
  • +
  • to_no_isolates() identifies and returns a network +including only nodes with at least one tie.
  • +
  • to_subgraph() returns only a subgraph of the network +based on e.g. some nodal attribute.
  • +
  • to_ties() returns a network where the ties in the +original network become the nodes, and the ties are shared adjacencies +to nodes.
  • +
  • to_matching() returns a network in which each node is +only tied to one of its previously existing ties such that the network’s +cardinality is maximised.
  • +
+
+
+
+
    +
  1. There are a few exceptions to this in the +{manynet} package, or when attributes of the network are +listed (see below).↩︎

  2. +
+
+
+

Adding data

+

If you import one or more edgelists and nodelists, it can be useful +to bind these together in an igraph, tidygraph, or network class +object.

+

Adding nodal attributes to a given network is relatively +straightforward. {manynet} offers a more +{igraph}-like syntax, +e.g. add_node_attribute(), as well as a more +{dplyr}-like syntax, e.g. mutate(), for those +already familiar with these tools in R:

+
+
ison_adolescents %>% 
+  mutate(color = "red",
+         degree = 1:8) %>% 
+  mutate_ties(weight = 1:10)
+ +
+

Note that to use {dplyr}-like functions like +mutate(), rename(), filter(), +select(), or join() on network ties, you will +need to append the function name with _ties. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + +
+
+
+ +
+ +
+
+
+
+ + +
+

Data

+

by James Hollway

+
+ + +
+
+
+
+ + +
+
+ + + + + + + + + + + + + + + + diff --git a/inst/tutorials/tutorial1/data/adols.csv b/inst/tutorials/tutorial1/data/adols.csv new file mode 100644 index 0000000..ed05f8b --- /dev/null +++ b/inst/tutorials/tutorial1/data/adols.csv @@ -0,0 +1,11 @@ +"from","to" +"Betty","Sue" +"Sue","Alice" +"Alice","Jane" +"Sue","Dale" +"Alice","Dale" +"Jane","Dale" +"Sue","Pam" +"Alice","Pam" +"Pam","Carol" +"Carol","Tina" diff --git a/inst/tutorials/tutorial1/data/adols.net b/inst/tutorials/tutorial1/data/adols.net new file mode 100644 index 0000000..3f13dde --- /dev/null +++ b/inst/tutorials/tutorial1/data/adols.net @@ -0,0 +1,12 @@ +*Vertices 8 +*Edges +1 2 +2 3 +3 4 +2 5 +3 5 +4 5 +2 6 +3 6 +6 7 +7 8 diff --git a/inst/tutorials/tutorial1/data/adols.paj b/inst/tutorials/tutorial1/data/adols.paj new file mode 100644 index 0000000..3f13dde --- /dev/null +++ b/inst/tutorials/tutorial1/data/adols.paj @@ -0,0 +1,12 @@ +*Vertices 8 +*Edges +1 2 +2 3 +3 4 +2 5 +3 5 +4 5 +2 6 +3 6 +6 7 +7 8 diff --git a/inst/tutorials/tutorial1/data/flonode.csv b/inst/tutorials/tutorial1/data/flonode.csv new file mode 100644 index 0000000..e48f9a8 --- /dev/null +++ b/inst/tutorials/tutorial1/data/flonode.csv @@ -0,0 +1,17 @@ +"name" +"Acciaiuoli" +"Albizzi" +"Barbadori" +"Bischeri" +"Castellani" +"Ginori" +"Guadagni" +"Lamberteschi" +"Medici" +"Pazzi" +"Peruzzi" +"Pucci" +"Ridolfi" +"Salviati" +"Strozzi" +"Tornabuoni" diff --git a/inst/tutorials/tutorial2/visualisation.Rmd b/inst/tutorials/tutorial2/visualisation.Rmd new file mode 100644 index 0000000..53dfb3d --- /dev/null +++ b/inst/tutorials/tutorial2/visualisation.Rmd @@ -0,0 +1,305 @@ +--- +title: "Visualisation" +author: "by James Hollway" +output: + learnr::tutorial: + theme: journal +runtime: shiny_prerendered +--- + +```{r setup, include=FALSE} +library(learnr) +library(manynet) +library(migraph) +library(patchwork) +knitr::opts_chunk$set(echo = FALSE) +``` + +## Why we graph + +Network visualisation is important and non-trivial. +As Tufte (1983: 9) said: + +> "At their best, graphics are instruments for reasoning about quantitative information. Often the most effective way to describe, explore, and summarize a set of numbers – even a very large set – is to look at pictures of those numbers" + +Brandes et al (1999) argue that visualising networks demands thinking about: + +- _substance_: a concise and precise delivery of insights to the researcher and/or readers +- _design_: the ergonomics of function are 98% of the purpose of good design, aesthetics only 2% +- and _algorithm_: the features of the e.g. the layout algorithm + +While there may be many dead-ends to exploratory visualisation, +it is worth taking the time to make sure that your main points are +easy to appreciate. + +On [her excellent and helpful website](https://kateto.net/network-visualization), +Katya Ognyanova outlines some key dimensions of control +that network researchers have to play with: + +- vertex position (layout) +- vertex shape +- vertex color +- vertex size +- vertex labels +- edge color +- edge size +- edge shape +- edge arrows + +## Approaches to visualising networks in R + +There are a host of packages for plotting in R, +and for plotting networks in R. +Plotting in R is typically based around two main approaches: +the 'base' approach in R by default, +and the 'grid' approach made popular by the famous and very flexible `{ggplot2}` package.^['gg' stands for the Grammar of Graphics.] +Approaches to plotting _graphs_ or _networks_ in R can be similarly divided. + +The two classic packages are `{igraph}` and `{sna}`, both building upon the base R graphics engine. +Newer packages [`{ggnetwork}`](https://www.r-bloggers.com/2016/03/ggnetwork-network-geometries-for-ggplot2/) and +[`{ggraph}`](https://ggraph.data-imaginist.com/index.html) build upon a grid approach.^[ +Others include: 'Networkly' for creating 2-D and 3-D interactive networks +that can be rendered with plotly and can be easily integrated into +shiny apps or markdown documents; +'visNetwork' interacts with javascript (vis.js) to make interactive networks +(http://datastorm-open.github.io/visNetwork/); and +'networkD3' interacts with javascript (D3) to make interactive networks +(https://www.r-bloggers.com/2016/10/network-visualization-part-6-d3-and-r-networkd3/). +] +This vignette introduces some functions in the `{manynet}` package for plotting and +visualising network data. +`{manynet}` builds upon the ggplot2/ggraph engine for plotting. + +## Using `{manynet}` to quickly plot network graphs + +To get a basic visualisation of the network before adding various specifications, +the `autographr()` function in `{manynet}` is a quick and easy way +to obtain a clear first look of the network +for preliminary investigations and understanding of the network. + +```{r manyneteg, exercise=TRUE} + +``` + +```{r manyneteg-solution} +library(manynet) +autographr(ison_brandes) +``` + +We can also specify the colours, groups, shapes, and sizes of nodes in +the `autographr()` function using the following parameters: + +* `node_colour` +* `node_shape` +* `node_size` + +### Adding titles and subtitles + +Append `ggtitle()` to add a title. +`{manynet}` works well with both `{ggplot2}` and `{ggraph}` functions +that can be appended to create more tailored visualisations +of the network. + +```{r manynetexample2, exercise=TRUE} + +``` + +```{r manynetexample2-solution} +autographr(ison_adolescents, + labels = TRUE, + node_size = 1.5) + + ggtitle("Visualisation") +``` + +`{manynet}` also uses the `{patchwork}` package for arranging +graphs together, e.g. side-by-side or above one another. +The syntax is quite straight forward and is used throughout these vignettes. + +```{r patchwork, exercise=TRUE} + +``` + +```{r patchwork-solution} +autographr(ison_adolescents) + autographr(ison_algebra) +autographr(ison_adolescents) / autographr(ison_algebra) +``` + +### Adding legends + +By default, `{manynet}` doesn't add legends automatically, +as often the colours are pretty self-explanatory, +for example in the following figure. + +```{r maxbet} +ison_adolescents %>% + mutate(maxbet = node_is_max(node_betweenness(ison_adolescents))) %>% + autographr(node_color = "maxbet") +``` + +But other times it is important to add in a legend. +`{manynet}` supports the `{ggplot2}` way of adding legends +after the main plot has been constructed, +using `guides()` to add in the legends, +and `labs()` for giving those legends particular titles. + +```{r discipline, exercise = TRUE} + +``` + +```{r discipline-solution} +ison_networkers %>% + autographr(node_color = "Discipline") + + guides(color = "legend") + + labs(color = "Discipline") +``` + +```{r discq} +question("What discipline is Charles Kadushin in according to this graph?", + answer("Anthropology"), + answer("Mathematics/Statistics"), + answer("Other"), + answer("Sociology", correct = TRUE), + allow_retry = TRUE, random_answer_order = TRUE) +``` + +### Layouts + +A range of graph layouts are available across the `{igraph}`, `{graphlayouts}`, and `{manynet}` packages +that can be used together with `autographr()`. + +```{r layoutseg, exercise=TRUE} + +``` + +```{r layoutseg-solution} +(autographr(ison_southern_women, layout = "bipartite") + ggtitle("bipartite") | +autographr(ison_southern_women, layout = "kk") + ggtitle("kk")) +``` + +### Using different colours + +Because the autographr function is based on +the grammar of graphics, +it's easy to extend or alter aesthetic aspects. +Here let's try and change the colors +assigned to the different regions in the `mpn_elite_mex` dataset. + +```{r colorch, exercise=TRUE} + +``` + +```{r colorch-solution} +autographr(mpn_elite_mex, + node_color = "region") + +autographr(mpn_elite_mex, + node_color = "region") + + ggplot2::scale_colour_hue() + +autographr(mpn_elite_mex, + node_color = "region") + + ggplot2::scale_colour_grey() + +autographr(mpn_elite_mex, + node_color = "region") + + ggplot2::scale_colour_manual( + values = c("1" = "red", + "3" = "blue", + "2" = "green")) +``` + +## Using `{ggraph}` for more flexibility + +For more flexibility with visualizations, +`{manynet}` users are encouraged to use the excellent `{ggraph}` package. +`{ggraph}` is built upon the venerable `{ggplot2}` package +and works with `tbl_graph` and `igraph` objects. +As with `{ggplot2}`, `{ggraph}` users are expected to build +a particular plot from the ground up, +adding explicit layers to visualise the nodes and edges. + +```{r ggrapheg, exercise=TRUE} + +``` + +```{r ggrapheg-solution} +library(ggraph) +ggraph(mpn_elite_mex, layout = "fr") + + geom_edge_link(edge_colour = "dark grey", + arrow = arrow(angle = 45, + length = unit(2, "mm"), + type = "closed"), + end_cap = circle(3, "mm")) + + geom_node_point(size = 2.5, shape = 19, colour = "blue") + + geom_node_text(aes(label=name), family = "serif", size = 2.5) + + scale_edge_width(range = c(0.3,1.5)) + + theme_graph() + + theme(legend.position = "none") +``` + +As we can see in the code above, we can specify various aspects of the plot to +tailor it to our network. +Firstly, we can alter the **layout** of the network using the `layout =` argument +to create a clearer visualisation of the ties between nodes. +This is especially important for larger networks, where nodes and ties are more +easily obscured or misrepresented. +In `{ggraph}`, the default layout is the "stress" layout. +The "stress" layout is a safe choice because it is deterministic and +fits well with almost any graph, but it is also a good idea to explore and try +out other layouts on your data. +More layouts can be found in the `{graphlayouts}` and `{igraph}` R packages. +To use a layout from the `{igraph}` package, enter only the last part of the layout +algorithm name (eg. `layout = "mds"` for "layout_with_mds"). + +Secondly, using `geom_node_point()` which draws the nodes as geometric shapes +(circles, squares, or triangles), we can specify the presentation of **nodes** +in the network in terms of their *shape* (`shape=`, choose from 1 to 21), +*size* (`size=`), or *colour* (`colour=`). We can also use `aes()` to match to +node attributes. To add labels, use `geom_node_text()` or +`geom_node_label()` (draws labels within a box). The font (`family=`), +font size (`size=`), and colour (`colour=`) of the labels can be specified. + +Thirdly, we can also specify the presentation of **edges** in the network. +To draw edges, we use `geom_edge_link0()` or `geom_edge_link()`. +Using the latter function makes it possible to draw a straight line with a +gradient. +The following features can be tailored either globally or matched to specific +edge attributes using `aes()`: + +* *colour*: `edge_colour=` + +* *width*: `edge_width=` + +* *linetype*: `edge_linetype=` + +* *opacity*: `edge_alpha=` + +For directed graphs, arrows can be drawn using the `arrow=` argument and the +`arrow()` function from `{ggplot2}`. The angle, length, arrowhead type, and +padding between the arrowhead and the node can also be specified. + +To change the position of the legend, add the `theme()` function from `{ggplot2}`. +The legend can be positioned at the top, bottom, left, or right, +or removed using "none". + +For more see David Schoch's [excellent resources on this](http://mr.schochastics.net/netVizR.html). + +## Exporting plots to PDF + +We can print the plots we have made to PDF by point-and-click +by selecting 'Save as PDF...' from under the 'Export' dropdown menu +in the plots panel tab of RStudio. + +If you want to do this programmatically, +say because you want to record how you have saved it so that you can +e.g. make some changes to the parameters at some point, +this is also not too difficult. + +After running the (gg-based) plot you want to save, +use the command `ggsave("my_filename.pdf")` to save your plot +as a PDF to your working directory. +If you want to save it somewhere else, you will need to specify the file path +(or change the working directory, but that might be more cumbersome). +If you want to save it as a different filetype, +replace `.pdf` with e.g. `.png` or `.jpeg`. +See `?ggsave` for more. diff --git a/inst/tutorials/tutorial2/visualisation.html b/inst/tutorials/tutorial2/visualisation.html new file mode 100644 index 0000000..e3f8596 --- /dev/null +++ b/inst/tutorials/tutorial2/visualisation.html @@ -0,0 +1,855 @@ + + + + + + + + + + + + + + + + + +Visualisation + + + + + + + + + + + + + + + + + + + + + +Skip to Tutorial Content + + + +
+
+ +
+ +
+

Why we graph

+

Network visualisation is important and non-trivial. As Tufte (1983: +9) said:

+
+

“At their best, graphics are instruments for reasoning about +quantitative information. Often the most effective way to describe, +explore, and summarize a set of numbers – even a very large set – is to +look at pictures of those numbers”

+
+

Brandes et al (1999) argue that visualising networks demands thinking +about:

+
    +
  • substance: a concise and precise delivery of insights to +the researcher and/or readers
  • +
  • design: the ergonomics of function are 98% of the purpose +of good design, aesthetics only 2%
  • +
  • and algorithm: the features of the e.g. the layout +algorithm
  • +
+

While there may be many dead-ends to exploratory visualisation, it is +worth taking the time to make sure that your main points are easy to +appreciate.

+

On her excellent +and helpful website, Katya Ognyanova outlines some key dimensions of +control that network researchers have to play with:

+
    +
  • vertex position (layout)
  • +
  • vertex shape
  • +
  • vertex color
  • +
  • vertex size
  • +
  • vertex labels
  • +
  • edge color
  • +
  • edge size
  • +
  • edge shape
  • +
  • edge arrows
  • +
+
+
+

Approaches to visualising networks in R

+

There are a host of packages for plotting in R, and for plotting +networks in R. Plotting in R is typically based around two main +approaches: the ‘base’ approach in R by default, and the ‘grid’ approach +made popular by the famous and very flexible {ggplot2} +package.1 Approaches to plotting +graphs or networks in R can be similarly divided.

+

The two classic packages are {igraph} and +{sna}, both building upon the base R graphics engine. Newer +packages {ggnetwork} +and {ggraph} +build upon a grid approach.2 This vignette introduces some +functions in the {manynet} package for plotting and +visualising network data. {manynet} builds upon the +ggplot2/ggraph engine for plotting.

+
+
+
+
    +
  1. ‘gg’ stands for the Grammar of Graphics.↩︎

  2. +
  3. Others include: ‘Networkly’ for creating 2-D +and 3-D interactive networks that can be rendered with plotly and can be +easily integrated into shiny apps or markdown documents; ‘visNetwork’ +interacts with javascript (vis.js) to make interactive networks (http://datastorm-open.github.io/visNetwork/); and +‘networkD3’ interacts with javascript (D3) to make interactive networks +(https://www.r-bloggers.com/2016/10/network-visualization-part-6-d3-and-r-networkd3/).↩︎

  4. +
+
+
+

Using {manynet} to quickly plot network graphs

+

To get a basic visualisation of the network before adding various +specifications, the autographr() function in +{manynet} is a quick and easy way to obtain a clear first +look of the network for preliminary investigations and understanding of +the network.

+
+ +
+
+
library(manynet)
+autographr(ison_brandes)
+
+

We can also specify the colours, groups, shapes, and sizes of nodes +in the autographr() function using the following +parameters:

+
    +
  • node_colour
  • +
  • node_shape
  • +
  • node_size
  • +
+
+

Adding titles and subtitles

+

Append ggtitle() to add a title. {manynet} +works well with both {ggplot2} and {ggraph} +functions that can be appended to create more tailored visualisations of +the network.

+
+ +
+
+
autographr(ison_adolescents,
+           labels = TRUE,
+           node_size = 1.5) + 
+  ggtitle("Visualisation")
+
+

{manynet} also uses the {patchwork} package +for arranging graphs together, e.g. side-by-side or above one another. +The syntax is quite straight forward and is used throughout these +vignettes.

+
+ +
+
+
autographr(ison_adolescents) + autographr(ison_algebra)
+autographr(ison_adolescents) / autographr(ison_algebra)
+
+
+
+

Adding legends

+

By default, {manynet} doesn’t add legends automatically, +as often the colours are pretty self-explanatory, for example in the +following figure.

+

+

But other times it is important to add in a legend. +{manynet} supports the {ggplot2} way of adding +legends after the main plot has been constructed, using +guides() to add in the legends, and labs() for +giving those legends particular titles.

+
+ +
+
+
ison_networkers %>% 
+  autographr(node_color = "Discipline") +
+  guides(color = "legend") + 
+  labs(color = "Discipline")
+
+
+
+
+
+
+ +
+
+
+
+

Layouts

+

A range of graph layouts are available across the +{igraph}, {graphlayouts}, and +{manynet} packages that can be used together with +autographr().

+
+ +
+
+
(autographr(ison_southern_women, layout = "bipartite") + ggtitle("bipartite") |
+autographr(ison_southern_women, layout = "kk") + ggtitle("kk"))
+
+
+
+

Using different colours

+

Because the autographr function is based on the grammar of graphics, +it’s easy to extend or alter aesthetic aspects. Here let’s try and +change the colors assigned to the different regions in the +mpn_elite_mex dataset.

+
+ +
+
+
autographr(mpn_elite_mex,
+           node_color = "region")
+
+autographr(mpn_elite_mex,
+           node_color = "region") +
+  ggplot2::scale_colour_hue()
+
+autographr(mpn_elite_mex,
+           node_color = "region") +
+  ggplot2::scale_colour_grey()
+
+autographr(mpn_elite_mex,
+           node_color = "region") +
+  ggplot2::scale_colour_manual(
+    values = c("1" = "red",
+               "3" = "blue",
+               "2" = "green"))
+
+
+
+
+

Using {ggraph} for more flexibility

+

For more flexibility with visualizations, {manynet} +users are encouraged to use the excellent {ggraph} package. +{ggraph} is built upon the venerable {ggplot2} +package and works with tbl_graph and igraph +objects. As with {ggplot2}, {ggraph} users are +expected to build a particular plot from the ground up, adding explicit +layers to visualise the nodes and edges.

+
+ +
+
+
library(ggraph)
+ggraph(mpn_elite_mex, layout = "fr") + 
+  geom_edge_link(edge_colour = "dark grey", 
+                  arrow = arrow(angle = 45,
+                                length = unit(2, "mm"),
+                                type = "closed"),
+                  end_cap = circle(3, "mm")) +
+  geom_node_point(size = 2.5, shape = 19, colour = "blue") +
+  geom_node_text(aes(label=name), family = "serif", size = 2.5) +
+  scale_edge_width(range = c(0.3,1.5)) +
+  theme_graph() +
+  theme(legend.position = "none")
+
+

As we can see in the code above, we can specify various aspects of +the plot to tailor it to our network. Firstly, we can alter the +layout of the network using the layout = +argument to create a clearer visualisation of the ties between nodes. +This is especially important for larger networks, where nodes and ties +are more easily obscured or misrepresented. In {ggraph}, +the default layout is the “stress” layout. The “stress” layout is a safe +choice because it is deterministic and fits well with almost any graph, +but it is also a good idea to explore and try out other layouts on your +data. More layouts can be found in the {graphlayouts} and +{igraph} R packages. To use a layout from the +{igraph} package, enter only the last part of the layout +algorithm name (eg. layout = "mds" for +“layout_with_mds”).

+

Secondly, using geom_node_point() which draws the nodes +as geometric shapes (circles, squares, or triangles), we can specify the +presentation of nodes in the network in terms of their +shape (shape=, choose from 1 to 21), size +(size=), or colour (colour=). We can +also use aes() to match to node attributes. To add labels, +use geom_node_text() or geom_node_label() +(draws labels within a box). The font (family=), font size +(size=), and colour (colour=) of the labels +can be specified.

+

Thirdly, we can also specify the presentation of +edges in the network. To draw edges, we use +geom_edge_link0() or geom_edge_link(). Using +the latter function makes it possible to draw a straight line with a +gradient. The following features can be tailored either globally or +matched to specific edge attributes using aes():

+
    +
  • colour: edge_colour=

  • +
  • width: edge_width=

  • +
  • linetype: edge_linetype=

  • +
  • opacity: edge_alpha=

  • +
+

For directed graphs, arrows can be drawn using the +arrow= argument and the arrow() function from +{ggplot2}. The angle, length, arrowhead type, and padding +between the arrowhead and the node can also be specified.

+

To change the position of the legend, add the theme() +function from {ggplot2}. The legend can be positioned at +the top, bottom, left, or right, or removed using “none”.

+

For more see David Schoch’s excellent resources on +this.

+
+
+

Exporting plots to PDF

+

We can print the plots we have made to PDF by point-and-click by +selecting ‘Save as PDF…’ from under the ‘Export’ dropdown menu in the +plots panel tab of RStudio.

+

If you want to do this programmatically, say because you want to +record how you have saved it so that you can e.g. make some changes to +the parameters at some point, this is also not too difficult.

+

After running the (gg-based) plot you want to save, use the command +ggsave("my_filename.pdf") to save your plot as a PDF to +your working directory. If you want to save it somewhere else, you will +need to specify the file path (or change the working directory, but that +might be more cumbersome). If you want to save it as a different +filetype, replace .pdf with e.g. .png or +.jpeg. See ?ggsave for more. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + +
+ +
+ +
+
+
+
+ + +
+

Visualisation

+

by James Hollway

+
+ + +
+
+
+
+ + +
+
+ + + + + + + + + + + + + + + + diff --git a/inst/tutorials/tutorial2/visualisation_files/figure-html/maxbet-1.png b/inst/tutorials/tutorial2/visualisation_files/figure-html/maxbet-1.png new file mode 100644 index 0000000..2078d2a Binary files /dev/null and b/inst/tutorials/tutorial2/visualisation_files/figure-html/maxbet-1.png differ diff --git a/man/add.Rd b/man/add.Rd index 22a5ee4..16ac1cd 100644 --- a/man/add.Rd +++ b/man/add.Rd @@ -3,6 +3,7 @@ \name{add} \alias{add} \alias{add_nodes} +\alias{delete_nodes} \alias{add_ties} \alias{add_node_attribute} \alias{add_tie_attribute} @@ -10,6 +11,8 @@ \usage{ add_nodes(.data, nodes, attribute = NULL) +delete_nodes(.data, nodes) + add_ties(.data, ties, attribute = NULL) add_node_attribute(.data, attr_name, vector) @@ -17,7 +20,7 @@ add_node_attribute(.data, attr_name, vector) add_tie_attribute(.data, attr_name, vector) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -43,10 +46,20 @@ A data object of the same class as the function was given. These functions allow users to add nodes, ties, or attributes to the nodes or ties of a network. The \verb{add_*()} functions operate similarly to in \code{{igraph}}. + +Not all functions have methods available for all object classes. +Below are the currently implemented S3 methods:\tabular{lrrr}{ + \tab igraph \tab network \tab tbl_graph \cr + add_nodes \tab 1 \tab 1 \tab 1 \cr + add_ties \tab 1 \tab 1 \tab 1 \cr + delete_nodes \tab 1 \tab 0 \tab 0 \cr +} } \section{Functions}{ \itemize{ -\item \code{add_nodes()}: Add additional ties to a network +\item \code{add_nodes()}: Add additional nodes to a network + +\item \code{delete_nodes()}: Delete nodes in a network \item \code{add_ties()}: Add additional ties to a network diff --git a/man/as.Rd b/man/as.Rd index f3d9c28..7c726cf 100644 --- a/man/as.Rd +++ b/man/as.Rd @@ -26,7 +26,7 @@ as_siena(.data, twomode = FALSE) as_graphAM(.data, twomode = NULL) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} diff --git a/man/attributes.Rd b/man/attributes.Rd index 226cd11..cd3e91f 100644 --- a/man/attributes.Rd +++ b/man/attributes.Rd @@ -23,7 +23,7 @@ tie_weights(.data) tie_signs(.data) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -69,6 +69,7 @@ tie_signs(ison_marvel_relationships) Other mapping: \code{\link{auto_graph}}, \code{\link{is}()}, +\code{\link{partition_layouts}}, \code{\link{properties}} } \concept{mapping} diff --git a/man/auto_graph.Rd b/man/auto_graph.Rd index 484efaf..66f120a 100644 --- a/man/auto_graph.Rd +++ b/man/auto_graph.Rd @@ -14,7 +14,7 @@ http://blog.schochastics.net/post/animating-network-evolutions-with-gganimate/ \usage{ autographr( .data, - layout = "stress", + layout = NULL, labels = TRUE, node_color = NULL, node_shape = NULL, @@ -100,17 +100,32 @@ with sensible defaults }} \examples{ -ison_adolescents \%>\% - mutate(shape = rep(c("circle", "square"), times = 4), - color = rep(c("blue", "red"), times = 4)) \%>\% - autographr(node_shape = "shape", node_color = "color") -autographr(ison_karateka, node_size = 8) - autographs(to_egos(ison_adolescents)) +#ison_adolescents \%>\% +# mutate(shape = rep(c("circle", "square"), times = 4), +# color = rep(c("blue", "red"), times = 4)) \%>\% +# autographr(node_shape = "shape", node_color = "color") +#autographr(ison_karateka, node_size = 8) +#autographs(to_egos(ison_adolescents)) +#ison_adolescents \%>\% +# mutate_ties(year = sample(1995:1998, 10, replace = TRUE)) \%>\% +# to_waves(attribute = "year") \%>\% +# autographd() +#ison_adolescents \%>\% +# mutate(shape = rep(c("circle", "square"), times = 4), +# color = rep(c("blue", "red"), times = 4), +# size = sample(4:16, 8, replace = TRUE)) \%>\% +# mutate_ties(year = sample(1995:1998, 10, replace = TRUE), +# e_color = sample(c("yellow", "green"), 10, replace = TRUE)) \%>\% +# to_waves(attribute = "year") \%>\% +# autographd(keep_isolates = FALSE, layout = "circle", node_shape = "shape", +# node_color = "color", node_size = "size", +# edge_color = "e_color") } \seealso{ Other mapping: \code{\link{attributes}()}, \code{\link{is}()}, +\code{\link{partition_layouts}}, \code{\link{properties}} } \concept{mapping} diff --git a/man/create.Rd b/man/create.Rd index 4c034c2..9a85f35 100644 --- a/man/create.Rd +++ b/man/create.Rd @@ -10,6 +10,7 @@ \alias{create_lattice} \alias{create_components} \alias{create_core} +\alias{create_explicit} \title{Make networks with defined structures} \usage{ create_empty(n, directed = FALSE) @@ -27,6 +28,8 @@ create_lattice(n, directed = FALSE, width = 8) create_components(n, directed = FALSE, membership = NULL) create_core(n, directed = FALSE, membership = NULL) + +create_explicit(...) } \arguments{ \item{n}{Given: @@ -103,6 +106,9 @@ into separate components. being core nodes, densely tied to each other and peripheral nodes, and the rest peripheral, tied only to the core. +\item \code{create_explicit()}: Creates a network based on explicitly +named nodes and ties between them. + }} \section{Lattice graphs}{ @@ -134,10 +140,15 @@ create_tree(c(7,8)) create_lattice(12, width = 4) create_components(10, membership = c(1,1,1,2,2,2,3,3,3,3)) create_core(6) + create_explicit(A -+ B, B -+ C, A +-+ C, D) } \seealso{ \link{as} +\code{\link[igraph:graph_from_literal]{igraph::graph_from_literal()}} which \code{create_explicit()} mostly just wraps. +\code{create_explicit()} will also accept character input and not just a formula though, +and will never simplify the result. + Other makes: \code{\link{as}()}, \code{\link{generate}}, diff --git a/man/figures/README-import-graph-1.png b/man/figures/README-import-graph-1.png index e3878ae..74dff68 100644 Binary files a/man/figures/README-import-graph-1.png and b/man/figures/README-import-graph-1.png differ diff --git a/man/figures/README-layout-comparison-1.png b/man/figures/README-layout-comparison-1.png index f53e023..9c448df 100644 Binary files a/man/figures/README-layout-comparison-1.png and b/man/figures/README-layout-comparison-1.png differ diff --git a/man/from.Rd b/man/from.Rd index d82504b..fc562bc 100644 --- a/man/from.Rd +++ b/man/from.Rd @@ -17,7 +17,7 @@ from_waves(.data) from_slices(.data, remove.duplicates = FALSE) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} diff --git a/man/generate.Rd b/man/generate.Rd index 5fa1691..8dd9b33 100644 --- a/man/generate.Rd +++ b/man/generate.Rd @@ -42,7 +42,7 @@ By default TRUE.} \item{width}{Integer specifying the width of the ring, breadth of the branches, or maximum extent of the neighbourbood.} -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -95,15 +95,24 @@ or on each of the rows and columns (for a two-mode network). }} \examples{ -autographr(generate_random(12, 0.4)) -autographr(generate_random(c(6, 6), 0.4)) -autographr(generate_smallworld(12, 0.025)) -autographr(generate_smallworld(12, 0.25)) -autographr(generate_smallworld(c(6,6), 0.025)) -autographr(generate_scalefree(12, 0.25)) -autographr(generate_scalefree(12, 1.25)) -autographr(generate_scalefree(c(12,6), 0.25)) -autographr(generate_scalefree(c(12,6), 1.25)) +generate_random(12, 0.4) +generate_random(c(6, 6), 0.4) +#autographr(generate_random(12, 0.4)) +#autographr(generate_random(c(6, 6), 0.4)) +generate_smallworld(12, 0.025) +generate_smallworld(12, 0.25) +generate_smallworld(c(6,6), 0.025) +#autographr(generate_smallworld(12, 0.025)) +#autographr(generate_smallworld(12, 0.25)) +#autographr(generate_smallworld(c(6,6), 0.025)) +generate_scalefree(12, 0.25) +generate_scalefree(12, 1.25) +generate_scalefree(c(12,6), 0.25) +generate_scalefree(c(12,6), 1.25) +#autographr(generate_scalefree(12, 0.25)) +#autographr(generate_scalefree(12, 1.25)) +#autographr(generate_scalefree(c(12,6), 0.25)) +#autographr(generate_scalefree(c(12,6), 1.25)) autographr(ison_adolescents) autographr(generate_permutation(ison_adolescents)) } diff --git a/man/is.Rd b/man/is.Rd index 9c688b5..a869fec 100644 --- a/man/is.Rd +++ b/man/is.Rd @@ -15,7 +15,15 @@ \alias{is_uniplex} \alias{is_longitudinal} \alias{is_dynamic} +\alias{is_connected} +\alias{is_perfect_matching} +\alias{is_eulerian} +\alias{is_acyclic} +\alias{is_aperiodic} \title{Describing network formats} +\source{ +https://stackoverflow.com/questions/55091438/r-igraph-find-all-cycles +} \usage{ is_manynet(.data) @@ -42,9 +50,19 @@ is_uniplex(.data) is_longitudinal(.data) is_dynamic(.data) + +is_connected(.data) + +is_perfect_matching(.data, mark = "type") + +is_eulerian(.data) + +is_acyclic(.data) + +is_aperiodic(.data, max_path_length = 4) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -52,13 +70,25 @@ is_dynamic(.data) \item network, from the \code{{network}} package \item tbl_graph, from the \code{{tidygraph}} package }} + +\item{mark}{A logical vector marking two types or modes. +By default "type".} + +\item{max_path_length}{Maximum path length considered. +If negative, paths of all lengths are considered. +By default 4, to avoid potentially very long computation times.} } \value{ +TRUE if the condition is met, or FALSE otherwise. + TRUE if the condition is met, or FALSE otherwise. } \description{ These functions implement logical tests for various network properties. All \verb{is_*()} functions return a logical scalar (TRUE or FALSE). + +These functions implement logical tests for various network +properties. } \section{Functions}{ \itemize{ @@ -90,6 +120,22 @@ or multiple columns to the edgelist. \item \code{is_dynamic()}: Tests whether network is dynamic, time-stamped data +\item \code{is_connected()}: Tests whether network is weakly connected if +the network is undirected or strongly connected if directed. +To test weak connection on a directed network, +please see \code{to_undirected()}. + +\item \code{is_perfect_matching()}: Tests whether there is a matching for a network +that covers every node in the network + +\item \code{is_eulerian()}: Tests whether there is a Eulerian path for a network +where that path passes through every tie exactly once +@importFrom igraph has_eulerian_path + +\item \code{is_acyclic()}: Tests whether network is a directed acyclic graph + +\item \code{is_aperiodic()}: Tests whether network is aperiodic + }} \examples{ is_manynet(create_filled(2)) @@ -107,11 +153,18 @@ is_multiplex(create_filled(c(3,3))) is_uniplex(create_star(3)) is_longitudinal(create_tree(5, 3)) is_dynamic(create_tree(3)) +is_connected(ison_southern_women) +is_perfect_matching(ison_southern_women) +is_eulerian(ison_brandes) +is_acyclic(ison_algebra) +is_aperiodic(ison_algebra) } \seealso{ Other mapping: \code{\link{attributes}()}, \code{\link{auto_graph}}, +\code{\link{partition_layouts}}, \code{\link{properties}} } \concept{mapping} +\concept{marks} diff --git a/man/ison_brandes.Rd b/man/ison_brandes.Rd index 942e3b8..95753b7 100644 --- a/man/ison_brandes.Rd +++ b/man/ison_brandes.Rd @@ -3,32 +3,18 @@ \docType{data} \name{ison_brandes} \alias{ison_brandes} -\alias{ison_brandes2} \title{One-mode and two-mode centrality demonstration networks} \format{ \if{html}{\out{
}}\preformatted{#> # A undirected tbl_graph with 11 nodes and 12 ties -#> # A tibble: 12 x 2 -#> from to -#> -#> 1 1 3 -#> 2 2 3 -#> 3 3 4 -#> 4 4 5 -#> 5 4 6 -#> 6 5 7 -#> # i 6 more rows -}\if{html}{\out{
}} - -\if{html}{\out{
}}\preformatted{#> # A two-mode tbl_graph with 11 nodes and 12 ties #> # A tibble: 11 x 1 -#> type -#> -#> 1 FALSE -#> 2 FALSE -#> 3 TRUE -#> 4 FALSE -#> 5 TRUE -#> 6 TRUE +#> twomode_type +#> +#> 1 FALSE +#> 2 FALSE +#> 3 TRUE +#> 4 FALSE +#> 5 TRUE +#> 6 TRUE #> # i 5 more rows #> # A tibble: 12 x 2 #> from to @@ -44,11 +30,11 @@ } \usage{ data(ison_brandes) - -data(ison_brandes2) } \description{ This network should solely be used for demonstration purposes as it does not describe a real network. +To convert into the two-mode version, +assign \code{ison_brandes \%>\% rename(type = twomode_type)}. } \keyword{datasets} diff --git a/man/ison_konigsberg.Rd b/man/ison_konigsberg.Rd new file mode 100644 index 0000000..6d917bd --- /dev/null +++ b/man/ison_konigsberg.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data_ison.R +\docType{data} +\name{ison_konigsberg} +\alias{ison_konigsberg} +\title{One-mode Seven Bridges of Konigsberg network (Euler 1741)} +\format{ +\if{html}{\out{
}}\preformatted{#> # A labelled, multiplex, undirected tbl_graph with 4 nodes and 7 ties +#> # A tibble: 4 x 3 +#> name lat lon +#> +#> 1 Altstadt 54.7 20.5 +#> 2 Kneiphof 54.7 20.5 +#> 3 Lomse 54.7 20.5 +#> 4 Vorstadt 54.7 20.5 +#> # A tibble: 7 x 2 +#> from to +#> +#> 1 1 2 +#> 2 1 2 +#> 3 1 3 +#> 4 2 3 +#> 5 2 4 +#> 6 2 4 +#> # i 1 more row +}\if{html}{\out{
}} +} +\usage{ +data(ison_konigsberg) +} +\description{ +One-mode Seven Bridges of Konigsberg network (Euler 1741) +} +\references{ +Euler, Leonard. 1741. “Solutio problematis ad geometriam situs pertinentis.” +\emph{Commentarii academiae scientiarum Petropolitanae}. +} +\keyword{datasets} diff --git a/man/ison_projection.Rd b/man/ison_laterals.Rd similarity index 68% rename from man/ison_projection.Rd rename to man/ison_laterals.Rd index cf7ffb0..deb2cf3 100644 --- a/man/ison_projection.Rd +++ b/man/ison_laterals.Rd @@ -1,36 +1,35 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/data_ison.R \docType{data} -\name{ison_projection} -\alias{ison_projection} -\alias{ison_mm} -\alias{ison_bm} -\alias{ison_mb} -\alias{ison_bb} +\name{ison_laterals} +\alias{ison_laterals} \title{Two-mode projection examples (Hollway 2021)} \format{ -\if{html}{\out{
}}\preformatted{#> # A labelled, two-mode tbl_graph with 6 nodes and 6 ties -#> # A tibble: 6 x 2 +\if{html}{\out{
}}\preformatted{#> $ison_bb +#> # A labelled, two-mode tbl_graph with 10 nodes and 12 ties +#> # A tibble: 10 x 2 #> name type #> #> 1 A FALSE -#> 2 M TRUE +#> 2 U TRUE #> 3 B FALSE -#> 4 C FALSE -#> 5 N TRUE -#> 6 D FALSE -#> # A tibble: 6 x 2 +#> 4 V TRUE +#> 5 C FALSE +#> 6 W TRUE +#> # i 4 more rows +#> # A tibble: 12 x 2 #> from to #> #> 1 1 2 -#> 2 3 2 -#> 3 3 5 -#> 4 4 2 -#> 5 4 5 -#> 6 6 5 -}\if{html}{\out{
}} - -\if{html}{\out{
}}\preformatted{#> # A labelled, two-mode tbl_graph with 8 nodes and 9 ties +#> 2 1 4 +#> 3 3 2 +#> 4 3 6 +#> 5 3 7 +#> 6 3 8 +#> # i 6 more rows +#> +#> $ison_bm +#> # A labelled, two-mode tbl_graph with 8 nodes and 9 ties #> # A tibble: 8 x 2 #> name type #> @@ -51,9 +50,9 @@ #> 5 3 7 #> 6 5 4 #> # i 3 more rows -}\if{html}{\out{
}} - -\if{html}{\out{
}}\preformatted{#> # A labelled, two-mode tbl_graph with 8 nodes and 9 ties +#> +#> $ison_mb +#> # A labelled, two-mode tbl_graph with 8 nodes and 9 ties #> # A tibble: 8 x 2 #> name type #> @@ -74,42 +73,36 @@ #> 5 4 2 #> 6 4 5 #> # i 3 more rows -}\if{html}{\out{
}} - -\if{html}{\out{
}}\preformatted{#> # A labelled, two-mode tbl_graph with 10 nodes and 12 ties -#> # A tibble: 10 x 2 +#> +#> $ison_mm +#> # A labelled, two-mode tbl_graph with 6 nodes and 6 ties +#> # A tibble: 6 x 2 #> name type #> #> 1 A FALSE -#> 2 U TRUE +#> 2 M TRUE #> 3 B FALSE -#> 4 V TRUE -#> 5 C FALSE -#> 6 W TRUE -#> # i 4 more rows -#> # A tibble: 12 x 2 +#> 4 C FALSE +#> 5 N TRUE +#> 6 D FALSE +#> # A tibble: 6 x 2 #> from to #> #> 1 1 2 -#> 2 1 4 -#> 3 3 2 -#> 4 3 6 -#> 5 3 7 -#> 6 3 8 -#> # i 6 more rows +#> 2 3 2 +#> 3 3 5 +#> 4 4 2 +#> 5 4 5 +#> 6 6 5 }\if{html}{\out{
}} } \usage{ -data(ison_mm) - -data(ison_bm) - -data(ison_mb) - -data(ison_bb) +data(ison_laterals) } \description{ -These datasets are for demonstration purposes and do not describe any real world network. +These networks are for demonstration purposes and do not describe any real world network. All examples contain named nodes. +The networks are gathered together as a list and can be retrieved simply by plucking +the desired network. } \keyword{datasets} diff --git a/man/ison_marvel.Rd b/man/ison_marvel.Rd index 64d5227..5c65d82 100644 --- a/man/ison_marvel.Rd +++ b/man/ison_marvel.Rd @@ -8,7 +8,10 @@ \title{Multilevel two-mode affiliation, signed one-mode networks of Marvel comic book characters (Yüksel 2017)} \format{ -\if{html}{\out{
}}\preformatted{#> # A labelled, two-mode tbl_graph with 194 nodes and 683 ties +\if{html}{\out{
}}\preformatted{#> This graph was created by an old(er) igraph version. +#> Call upgrade_graph() on it to use with the current igraph version +#> For now we convert it on the fly... +#> # A labelled, two-mode tbl_graph with 194 nodes and 683 ties #> # A tibble: 194 x 2 #> type name #> @@ -31,7 +34,10 @@ book characters (Yüksel 2017)} #> # i 677 more rows }\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{#> # A labelled, complex, multiplex, signed, undirected tbl_graph with 53 nodes and 558 ties +\if{html}{\out{
}}\preformatted{#> This graph was created by an old(er) igraph version. +#> Call upgrade_graph() on it to use with the current igraph version +#> For now we convert it on the fly... +#> # A labelled, complex, multiplex, signed, undirected tbl_graph with 53 nodes and 558 ties #> # A tibble: 53 x 10 #> name Gender Appearances Attractive Rich Intellect Omnilingual PowerOrigin #> diff --git a/man/miss.Rd b/man/miss.Rd index 3e6ca5b..4779f92 100644 --- a/man/miss.Rd +++ b/man/miss.Rd @@ -11,7 +11,7 @@ na_to_zero(.data) na_to_mean(.data) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} diff --git a/man/partition_layouts.Rd b/man/partition_layouts.Rd new file mode 100644 index 0000000..b727472 --- /dev/null +++ b/man/partition_layouts.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/map_layout_partition.R +\name{partition_layouts} +\alias{partition_layouts} +\alias{layout_tbl_graph_hierarchy} +\alias{layout_tbl_graph_alluvial} +\alias{layout_tbl_graph_railway} +\alias{layout_tbl_graph_ladder} +\alias{layout_tbl_graph_concentric} +\title{Layout algorithms based on bi- or other partitions} +\source{ +Diego Diez, Andrew P. Hutchins and Diego Miranda-Saavedra. 2014. +"Systematic identification of transcriptional regulatory modules from +protein-protein interaction networks". +\emph{Nucleic Acids Research}, 42 (1) e6. +} +\usage{ +layout_tbl_graph_hierarchy(.data, circular = FALSE, times = 1000) + +layout_tbl_graph_alluvial(.data, circular = FALSE, times = 1000) + +layout_tbl_graph_railway(.data, circular = FALSE, times = 1000) + +layout_tbl_graph_ladder(.data, circular = FALSE, times = 1000) + +layout_tbl_graph_concentric( + .data, + membership = NULL, + radius = NULL, + order.by = NULL, + circular = FALSE, + times = 1000 +) +} +\arguments{ +\item{.data}{An object of a \code{{manynet}}-consistent class: +\itemize{ +\item matrix (adjacency or incidence) from \code{{base}} R +\item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} +\item igraph, from the \code{{igraph}} package +\item network, from the \code{{network}} package +\item tbl_graph, from the \code{{tidygraph}} package +}} + +\item{circular}{Should the layout be transformed into a radial representation. +Only possible for some layouts. Defaults to FALSE} + +\item{times}{Maximum number of iterations, where appropriate} + +\item{membership}{A vector of partition memberships.} + +\item{radius}{A vector of radii at which the concentric circles +should be located. +By default this is equal placement around an empty centre, +unless one (the core) is a single node, +in which case this node occupies the centre of the graph.} + +\item{order.by}{An attribute label indicating the (decreasing) order +for the nodes around the circles. +By default ordering is given by a bipartite placement that reduces +the number of edge crossings.} +} +\description{ +These algorithms layout networks based on two or more partitions, +and are recommended for use with \code{autographr()} or \code{{ggraph}}. +Note that these layout algorithms use \code{{Rgraphviz}}, +a package that is only available on Bioconductor. +It will first need to be downloaded using \code{BiocManager::install("Rgraphviz")}. + +The "hierarchy" layout layers the first node set along the bottom, +and the second node set along the top, +sequenced and spaced as necessary to minimise edge overlap. +The "alluvial" layout is similar to "hierarchy", +but places successive layers horizontally rather than vertically. +The "railway" layout is similar to "hierarchy", +but nodes are aligned across the layers. +The "ladder" layout is similar to "railway", +but places successive layers horizontally rather than vertically. +The "concentric" layout places a "hierarchy" layout +around a circle, with successive layers appearing as concentric circles. +} +\seealso{ +Other mapping: +\code{\link{attributes}()}, +\code{\link{auto_graph}}, +\code{\link{is}()}, +\code{\link{properties}} +} +\concept{mapping} diff --git a/man/properties.Rd b/man/properties.Rd index 74e2cf9..81224a3 100644 --- a/man/properties.Rd +++ b/man/properties.Rd @@ -20,7 +20,7 @@ network_node_attributes(.data) network_tie_attributes(.data) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -68,6 +68,7 @@ network_dims(to_mode1(ison_southern_women)) Other mapping: \code{\link{attributes}()}, \code{\link{auto_graph}}, -\code{\link{is}()} +\code{\link{is}()}, +\code{\link{partition_layouts}} } \concept{mapping} diff --git a/man/read.Rd b/man/read.Rd index f7abe6c..2c1cb29 100644 --- a/man/read.Rd +++ b/man/read.Rd @@ -53,7 +53,7 @@ networks from a single UCINET file. Please convert these one by one.} \item{...}{Additional parameters passed to the read/write function.} -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} diff --git a/man/reformat.Rd b/man/reformat.Rd index 2195290..cdec793 100644 --- a/man/reformat.Rd +++ b/man/reformat.Rd @@ -47,7 +47,7 @@ to_multilevel(.data) to_twomode(.data, mark) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -80,21 +80,24 @@ These functions offer tools for reformatting migraph-consistent objects Unlike the \verb{as_*()} group of functions, these functions always return the same object type as they are given, only transforming these objects' properties. -} -\details{ -Since some modifications are easier to implement for some objects than others, -here are the currently implemented modifications:\tabular{lccccc}{ - to_ \tab edgelists \tab matrices \tab igraph \tab tidygraph \tab network \cr - unweighted \tab X \tab X \tab X \tab X \tab X \cr - undirected \tab \tab X \tab X \tab X \tab X \cr - redirected \tab X \tab X \tab X \tab X \tab \cr - unsigned \tab X \tab X \tab X \tab X \tab \cr - uniplex \tab \tab \tab X \tab X \tab \cr - unnamed \tab X \tab X \tab X \tab X \tab X \cr - named \tab X \tab X \tab X \tab X \tab X \cr - simplex \tab \tab X \tab X \tab X \tab \cr - onemode \tab \tab \tab X \tab X \tab \cr - multilevel \tab \tab X \tab X \tab X \tab \cr + +Not all functions have methods available for all object classes. +Below are the currently implemented S3 methods:\tabular{lrrrrr}{ + \tab data.frame \tab igraph \tab matrix \tab network \tab tbl_graph \cr + to_acyclic \tab 0 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_directed \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_multilevel \tab 0 \tab 1 \tab 1 \tab 0 \tab 1 \cr + to_named \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_onemode \tab 0 \tab 1 \tab 1 \tab 0 \tab 1 \cr + to_reciprocated \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_redirected \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_simplex \tab 0 \tab 1 \tab 1 \tab 0 \tab 1 \cr + to_twomode \tab 0 \tab 1 \tab 0 \tab 1 \tab 1 \cr + to_undirected \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_uniplex \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_unnamed \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_unsigned \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_unweighted \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr } } \section{Functions}{ diff --git a/man/split.Rd b/man/split.Rd index fc64345..90d8b06 100644 --- a/man/split.Rd +++ b/man/split.Rd @@ -20,7 +20,7 @@ to_waves(.data, attribute = "wave", panels = NULL) to_slices(.data, attribute = "time", slice = NULL) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -52,7 +52,17 @@ The returned object will be a list of network objects. } \description{ These functions offer tools for splitting manynet-consistent objects -(matrices, igraph, tidygraph, or network objects). +(matrices, igraph, tidygraph, or network objects) into lists of networks. + +Not all functions have methods available for all object classes. +Below are the currently implemented S3 methods:\tabular{lrrrrr}{ + \tab data.frame \tab igraph \tab matrix \tab network \tab tbl_graph \cr + to_components \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_egos \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_slices \tab 0 \tab 1 \tab 0 \tab 0 \tab 1 \cr + to_subgraphs \tab 0 \tab 1 \tab 0 \tab 1 \tab 1 \cr + to_waves \tab 1 \tab 1 \tab 0 \tab 0 \tab 1 \cr +} } \section{Functions}{ \itemize{ @@ -75,7 +85,7 @@ with some continuous time variable at some time slice(s). }} \examples{ to_egos(ison_adolescents) - autographs(to_egos(ison_adolescents,2)) + #autographs(to_egos(ison_adolescents,2)) ison_adolescents \%>\% mutate(unicorn = sample(c("yes", "no"), 8, replace = TRUE)) \%>\% diff --git a/man/themes.Rd b/man/themes.Rd new file mode 100644 index 0000000..f92e471 --- /dev/null +++ b/man/themes.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/map_theme.R +\name{themes} +\alias{themes} +\alias{theme_iheid} +\title{Theming ggraph} +\usage{ +theme_iheid(ggraph) +} +\arguments{ +\item{ggraph}{A ggraph object, e.g. created using \code{autographr()}} +} +\value{ +Themes the current ggraph to current IHEID guidelines. +} +\description{ +These functions enable graphs to be easily and quickly themed, +e.g. changing the default colour of the graph's vertices and edges. +Note that, unlike typical \code{{ggplot2}} theming, these functions +are passed the current plot with \verb{\%>\%} rather than \code{+}. +For example, \code{autographr(ison_konigsberg) \%>\% theme_iheid()}. +} diff --git a/man/tidy.Rd b/man/tidy.Rd index 03c600f..5522ca1 100644 --- a/man/tidy.Rd +++ b/man/tidy.Rd @@ -34,7 +34,7 @@ summarise_ties(.data, ...) bind_node_attributes(.data, object2) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} diff --git a/man/transform.Rd b/man/transform.Rd index 6e76e47..d43c3b9 100644 --- a/man/transform.Rd +++ b/man/transform.Rd @@ -9,6 +9,7 @@ \alias{to_ties} \alias{to_blocks} \alias{to_matching} +\alias{to_eulerian} \alias{to_anti} \alias{to_no_isolates} \title{Tools for transforming networks, graphs, and matrices} @@ -27,12 +28,14 @@ to_blocks(.data, membership, FUN = mean) to_matching(.data, mark = "type") +to_eulerian(.data) + to_anti(.data) to_no_isolates(.data) } \arguments{ -\item{.data}{An object of a manynet-consistent class: +\item{.data}{An object of a \code{{manynet}}-consistent class: \itemize{ \item matrix (adjacency or incidence) from \code{{base}} R \item edgelist, a data frame from \code{{base}} R or tibble from \code{{tibble}} @@ -82,18 +85,20 @@ These functions offer tools for transforming migraph-consistent objects (matrices, igraph, tidygraph, or network objects). Transforming means that the returned object may have different dimensions than the original object. -} -\details{ -Since some modifications are easier to implement for some objects than others, -here are the currently implemented modifications:\tabular{lccccc}{ - to_ \tab edgelists \tab matrices \tab igraph \tab tidygraph \tab network \cr - mode1 \tab X \tab X \tab X \tab X \tab X \cr - mode2 \tab X \tab X \tab X \tab X \tab X \cr - giant \tab X \tab X \tab X \tab X \tab X \cr - subgraph \tab X \tab X \tab X \tab X \tab X \cr - ties \tab X \tab X \tab X \tab X \tab X \cr - blocks \tab X \tab X \tab X \tab X \tab X \cr - matching \tab X \tab X \tab X \tab X \tab X \cr + +Not all functions have methods available for all object classes. +Below are the currently implemented S3 methods:\tabular{lrrrrrr}{ + \tab data.frame \tab igraph \tab list \tab matrix \tab network \tab tbl_graph \cr + to_anti \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_blocks \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_eulerian \tab 0 \tab 1 \tab 0 \tab 0 \tab 0 \tab 1 \cr + to_giant \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_matching \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_mode1 \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_mode2 \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_no_isolates \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \tab 1 \cr + to_subgraph \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr + to_ties \tab 1 \tab 1 \tab 0 \tab 1 \tab 1 \tab 1 \cr } } \section{Functions}{ @@ -126,6 +131,9 @@ while preserving the topology of the original structures. \item \code{to_matching()}: Returns a network with only matching ties +\item \code{to_eulerian()}: Returns a network with only +the Eulerian path + \item \code{to_anti()}: Returns the complement of a network where only ties \emph{not} present in the original network are included in the new network. @@ -149,11 +157,18 @@ where \eqn{n} is the number of nodes in the network. } \examples{ -autographr(to_mode1(ison_southern_women)) -autographr(to_mode2(ison_southern_women)) -autographr(to_ties(ison_adolescents)) -autographr(to_matching(ison_southern_women)) -autographr(to_anti(ison_southern_women)) +to_mode1(ison_southern_women) +to_mode2(ison_southern_women) +#autographr(to_mode1(ison_southern_women)) +#autographr(to_mode2(ison_southern_women)) +to_ties(ison_adolescents) +#autographr(to_ties(ison_adolescents)) +to_matching(ison_southern_women) +#autographr(to_matching(ison_southern_women)) + to_eulerian(delete_nodes(ison_konigsberg, "Lomse")) + #autographr(to_eulerian(delete_nodes(ison_konigsberg, "Lomse"))) +to_anti(ison_southern_women) +#autographr(to_anti(ison_southern_women)) ison_adolescents \%>\% activate(edges) \%>\% mutate(wave = sample(1995:1998, 10, replace = TRUE)) \%>\% diff --git a/tests/testthat/test-make_create.R b/tests/testthat/test-make_create.R index d4f319e..ee56b6b 100644 --- a/tests/testthat/test-make_create.R +++ b/tests/testthat/test-make_create.R @@ -69,3 +69,13 @@ test_that("core-periphery creation works", { # expect_s3_class(create_nest(2,4, as = "igraph"), "igraph") # expect_s3_class(create_nest(2,4, as = "tidygraph"), "tbl_graph") # }) + +test_that("nest creation works", { + expect_true(is_directed(create_explicit(A -+ B, B -+ C, A +-+ C, D))) + expect_false(manynet::is_weighted(create_explicit(A -+ B, B -+ C, A +-+ C, D))) + expect_length(create_explicit(A -+ B, B -+ C, A +-+ C, D), 4) + expect_s3_class(create_explicit(A -+ B, B -+ C, A +-+ C, D, as = "igraph"), + "igraph") + expect_s3_class(create_explicit(A -+ B, B -+ C, A +-+ C, D, as = "tidygraph"), + "tbl_graph") +}) diff --git a/tests/testthat/test-manip_add.R b/tests/testthat/test-manip_add.R index 63be7e5..2452803 100644 --- a/tests/testthat/test-manip_add.R +++ b/tests/testthat/test-manip_add.R @@ -68,3 +68,8 @@ test_that("summarise_ties works", { sum <- summarise_ties(orig, mean = mean(year)) expect_length(igraph::edge_attr(sum, "weight"), 93) }) + +test_that("delete_nodes works", { + expect_length(ison_adolescents, 8) + expect_length(delete_nodes(ison_adolescents, "Betty"), 7) +}) diff --git a/tests/testthat/test-manip_reformat.R b/tests/testthat/test-manip_reformat.R index f4011c3..0d61136 100644 --- a/tests/testthat/test-manip_reformat.R +++ b/tests/testthat/test-manip_reformat.R @@ -34,7 +34,7 @@ test_that("to_directed works",{ expect_true(is_directed(to_directed(as_igraph(ison_brandes)))) expect_true(is_directed(to_directed(as_matrix(ison_brandes)))) expect_true(is_directed(to_directed(as_network(ison_brandes)))) - # expect_true(is_directed(to_directed(ison_southern_women))) # twomode? + #expect_true(is_directed(to_directed(ison_southern_women))) # twomode? }) test_that("to_redirected works",{ @@ -79,7 +79,7 @@ test_that("to_reciprocated works",{ }) test_that("to_onemode works",{ - expect_false(is_twomode(to_onemode(ison_bm))) + expect_false(is_twomode(to_onemode(ison_southern_women))) expect_equal(c(to_onemode(ison_southern_women))[3], c(igraph::delete_vertex_attr(ison_southern_women, "type"))[3]) expect_equal(as_matrix(to_onemode(as_tidygraph(ison_southern_women))), diff --git a/tests/testthat/test-manip_transform.R b/tests/testthat/test-manip_transform.R index a136ed1..e2b71bd 100644 --- a/tests/testthat/test-manip_transform.R +++ b/tests/testthat/test-manip_transform.R @@ -99,3 +99,11 @@ test_that("to no isolates works", { expect_length(to_no_isolates(as_network(isolate)), 5) expect_equal(nrow(to_no_isolates(as_edgelist(isolate))), 5) }) + +test_that("to eulerian works", { + expect_true(is_eulerian(delete_nodes(ison_konigsberg, "Lomse"))) + expect_error(to_eulerian(ison_konigsberg), "This is not a Eulerian graph.") + expect_true(length(delete_nodes(ison_konigsberg, "Lomse")) == + length(to_eulerian(delete_nodes(ison_konigsberg, "Lomse")))) + expect_true(is_connected(to_eulerian(delete_nodes(ison_konigsberg, "Lomse")))) +}) diff --git a/tests/testthat/test-viz_autographr.R b/tests/testthat/test-map_autographr.R similarity index 87% rename from tests/testthat/test-viz_autographr.R rename to tests/testthat/test-map_autographr.R index 44a8b5c..aee9121 100644 --- a/tests/testthat/test-viz_autographr.R +++ b/tests/testthat/test-map_autographr.R @@ -1,7 +1,7 @@ -# Unweighted, unsigned, undirected network -test_brandes <- autographr(ison_brandes) - test_that("unweighted, unsigned, undirected networks graph correctly", { + skip_on_cran() + # Unweighted, unsigned, undirected network + test_brandes <- autographr(ison_brandes) # Node position expect_equal(round(test_brandes[["data"]][["x"]][[1]]), 3) expect_equal(round(test_brandes[["data"]][["y"]][[1]]), -1) @@ -13,10 +13,10 @@ test_that("unweighted, unsigned, undirected networks graph correctly", { expect_equal(as.character(test_brandes[["layers"]][[2]][["aes_params"]][["shape"]]), "circle") }) -# Unweighted, signed, undirected network -test_marvel <- autographr(to_giant(ison_marvel_relationships)) - test_that("unweighted, signed, undirected networks graph correctly", { + skip_on_cran() + # Unweighted, signed, undirected network + test_marvel <- autographr(to_giant(ison_marvel_relationships)) # Node position expect_equal(round(test_marvel[["data"]][["x"]][[1]]), -1) expect_equal(round(test_marvel[["data"]][["y"]][[1]]), 1) @@ -27,10 +27,10 @@ test_that("unweighted, signed, undirected networks graph correctly", { expect_equal(test_marvel[["layers"]][[3]][["aes_params"]][["shape"]], "circle") }) -# Unweighted, unsigned, directed network -test_algebra <- autographr(ison_algebra) - test_that("unweighted, unsigned, directed networks graph correctly", { + skip_on_cran() + # Unweighted, unsigned, directed network + test_algebra <- autographr(ison_algebra) # Node position expect_equal(round(test_algebra[["data"]][["x"]][[1]]), 0) expect_equal(round(test_algebra[["data"]][["y"]][[1]]), 0) @@ -45,10 +45,10 @@ test_that("unweighted, unsigned, directed networks graph correctly", { expect_equal(test_algebra[["layers"]][[3]][["aes_params"]][["shape"]], "circle") }) -# Weighted, unsigned, directed network -test_networkers <- autographr(ison_networkers) - test_that("weighted, unsigned, directed networks graph correctly", { + skip_on_cran() + # Weighted, unsigned, directed network + test_networkers <- autographr(ison_networkers) # Node position expect_equal(round(test_networkers[["data"]][["x"]][[1]]), 0) expect_equal(round(test_networkers[["data"]][["y"]][[1]]), 0) @@ -65,8 +65,10 @@ test_that("weighted, unsigned, directed networks graph correctly", { # Testing the node_color, node_size, and node_shape args by specifying a node attribute test_that("fancy node mods graph correctly", { + skip_on_cran() # one-mode network - ison_marvel_relationships <- dplyr::mutate(ison_marvel_relationships, nodesize = Appearances/1000) + ison_marvel_relationships <- dplyr::mutate(ison_marvel_relationships, + nodesize = Appearances/1000) testcolnodes <- autographr(ison_marvel_relationships, node_color = "Gender", node_size = "nodesize", @@ -84,14 +86,15 @@ test_that("fancy node mods graph correctly", { test2 <- autographr(ison_southern_women, node_color = "type") expect_s3_class(test2, c("ggraph","gg","ggplot")) - expect_equal(round(test2$data$x[1]), 1) - expect_equal(round(test2$data$y[1]), 1) + expect_equal(round(test2$data$x[1]), 0) + expect_equal(round(test2$data$y[1]), 0) expect_equal(nrow(test2[["plot_env"]][["lo"]]), network_nodes(ison_southern_women)) }) test_that("edge colours graph correctly", { - ison_brandes2 <-ison_brandes2 %>% + skip_on_cran() + ison_brandes2 <- ison_brandes %>% add_tie_attribute("tiecolour", c("A", "B", "A", "B", "B", "B", "B", "B", "B", "B", "B", "B")) test_brandes2 <- autographr(ison_brandes2, edge_color = "tiecolour") @@ -100,6 +103,7 @@ test_that("edge colours graph correctly", { # Named networks test_that("named networks plot correctly", { + skip_on_cran() onemode <- autographr(ison_adolescents) twomode <- autographr(ison_southern_women) expect_equal(onemode[["data"]][["name"]], node_names(ison_adolescents)) diff --git a/tests/testthat/test-mark_is.R b/tests/testthat/test-map_is.R similarity index 67% rename from tests/testthat/test-mark_is.R rename to tests/testthat/test-map_is.R index ace1b5a..168b438 100644 --- a/tests/testthat/test-mark_is.R +++ b/tests/testthat/test-map_is.R @@ -9,4 +9,9 @@ test_that("is tests work", { expect_true(is_manynet(ison_southern_women)) expect_true(is_graph(ison_southern_women)) expect_false(is_directed(as_network(ison_southern_women))) + expect_true(is_connected(ison_southern_women)) + expect_false(is_perfect_matching(ison_southern_women)) + expect_false(is_eulerian(ison_southern_women)) + expect_false(is_acyclic(ison_southern_women)) + expect_false(is_aperiodic(ison_southern_women)) }) diff --git a/tests/testthat/test_plots.R b/tests/testthat/test_plots.R new file mode 100644 index 0000000..b35c879 --- /dev/null +++ b/tests/testthat/test_plots.R @@ -0,0 +1,64 @@ +# # Test plot functions +# test_that("agreements_plot() returns the correct output format", { +# agreements <- data.frame(manyID = c("GEO-GRC[IEO]_2000P1", "GRC-TUR[HEP]_2000S", +# "KAZ-KGZ[RCT]_2000A", "BGR-URY[ORA]_2000A", +# "CRTBBD_2000P:CBD_1992A", "ESP-PRT[QRA]_2000A", +# "STP-EC[STP]_2000A", "KAZ-KGZ[CTR]_2000A", +# "EGY-GRC[OHA]_2000P5", "GT10PP_2000A"), +# Title = c("Protocol Of The 1 Session Of The Joint Intergovernmental Commission For Economic And Technical Cooperation Between Greece And Georgia", +# "Memorandum Of Understanding Between The Hellenic Republic And The Republic Of Turkey Concerning Cooperation On Environmental Protection", +# "AGREEMENT Between The Government Of The Kazakh Republic And The Government Of The Kyrgyz Republic On The Use Of Water Management Facilities Of Intergovernmental Status On The Rivers Chu And Talas", +# "Agreement Between The Oriental Republic Of Uruguay And The Republic Of Bulgaria On Antarctic Cooperation", +# "Cartagena Protocol On Biosafety To The Convention On Biological Diversity", +# "Agreement On Cooperation For The Protection And Sustainable Use Of The Waters Of The Spanish-Portuguese Hydrographic Basins Made Quotad Referendumquot In Albufeira On November 30 1998", +# "Agreement In The Form Of An Exchange Of Letters Concerning The Provisional Application Of The Protocol Setting Out For The Period 1 June 1999 To 31 May 2002 The Fishing Opportunities And The Financial Contribution Provided For By The Agreement Between The European Community And The Government Of The Democratic Republic Of Sao Tome E Principe On Fishing Off The Coast Of Sao Tome E Principe", +# "Agreement Between The Government Of The Republic Of Kazakhstan And The Government Of The Kyrgyz Republic On Utilization Of The Water Facilities Of Interstate Use On The Chu And Talas Rivers", +# "Protocol Of The 5 Session Of The Joint Ministerial Committee On Economic And Technical Cooperation Between The Hellenic Republic And The Arab Republic Of Egypt", +# "Multilateral Agreement Between The Governments Of The Treaty For A Customs Union And The Common Economic Space On Joint Exploration Of Outer Space For Peaceful Purposes"), +# Begin = c("2000-01-18", "2000-01-20", "2000-01-21", +# "2000-01-27", "2000-01-29", "2000-01-31", +# "2000-02-03", "2000-02-11", "2000-02-16", +# "2000-02-17"), +# DocType = c("B", "B", "B", "B", "M", "B", "B", "B", +# "B", "M")) +# p <- plot_agreements(agreements) +# expect_type(p, "list") +# expect_length(p, 9) +# expect_true(ggplot2::is.ggplot(p)) +# expect_named(p, c("data", "layers", "scales", "mapping", "theme", +# "coordinates", "facet", "plot_env", "labels")) +# expect_true(p[["plot_env"]][["layout"]] == "circle") +# }) +# +# test_that("membership_plot() returns the correct output format", { +# memberships <- data.frame(manyID = c("IE05PD_2000P:IE05PD_1971A", +# "IOPPRC_2000A", "IE05PD_2000P:IE05PD_1971A", +# "ICLOPD_2000P:CLC_1969A", +# "CTMHWD_2000E:CTMHWD_1989A", +# "INTRPP_2000S", "ICLOPD_2000P:CLC_1969A", +# "CF04TD_2000A", "TRNEIA_2000A", +# "IT04FF_2000E:CITES_1973A"), +# Title = c("Protocol Of 1992 To Amend The International Convention On The Establishment Of An International Fund For Compensation For Oil Pollution Damage 1971", +# "International Convention On Oil Pollution Preparedness Response And Cooperation", +# "Protocol Of 1992 To Amend The International Convention On The Establishment Of An International Fund For Compensation For Oil Pollution Damage 1971", +# "Protocol Of 1992 To Amend The International Convention On Civil Liability For Oil Pollution Damage 1969", +# "Amendment To The Basel Convention On The Control Of Transboundary Movements Of Hazardous Wastes And Their Disposal", +# "International Plant Protection Convention", +# "Protocol Of 1992 To Amend The International Convention On Civil Liability For Oil Pollution Damage 1969", +# "Cooperation Agreement On The Forecast Prevention And Mitigation Of Natural And Technological Disasters", +# "Convention On The Transboundary Effects Of Industrial Accidents", +# "Amendment To The Convention On International Trade In Endangered Species Of Wild Fauna And Flora (Art11)"), +# Begin = c("2000-01-05", "2000-01-05", "2000-01-06", +# "2000-01-06", "2000-01-12", "2000-01-12", +# "2000-01-15", "2000-01-19", "2000-01-20", +# "2000-01-20"), +# stateID = c("COG", "COM", "MDV", "MLT", "TTO", +# "LUX", "COM", "SVK", "HRV", "KEN")) +# p <- plot_memberships(memberships) +# expect_type(p, "list") +# expect_length(p, 9) +# expect_true(ggplot2::is.ggplot(p)) +# expect_named(p, c("data", "layers", "scales", "mapping", "theme", +# "coordinates", "facet", "plot_env", "labels")) +# expect_true(p[["plot_env"]][["layout"]] == "bipartite") +# })