From 7774c994f90878a74cceb5755a8051b4a890139a Mon Sep 17 00:00:00 2001 From: Brian Burns Date: Sun, 16 Dec 2018 20:07:16 -0600 Subject: [PATCH 01/18] version number update --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 49677270..cba692e7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: pkgnet Type: Package Title: Get Network Representation of an R Package -Version: 0.2.1.9000 +Version: 0.3.0 Authors@R: c( person("Brian", "Burns", email = "brian.burns@uptake.com", role = c("aut", "cre")), person("James", "Lamb", email = "james.lamb@uptake.com", role = c("aut")), From 930015845ae0dbdd4171df00cd39c16e06a410ff Mon Sep 17 00:00:00 2001 From: Brian Burns Date: Sun, 16 Dec 2018 20:07:32 -0600 Subject: [PATCH 02/18] created news.md --- NEWS.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 NEWS.md diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 00000000..1f91e9a8 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,18 @@ +# Version 0.3.0 + +## NEW FEATURES +* `InheritanceReporter`, a reporter to surface the R6 or S4 relationships within a package. +* Dropdown menu in graph visualizations for node selection. + +## CHANGES +* Edge direction reversed to align with UML class diagram convention. +* Default node colors are now colorblind accessible. +* Function network design utilizes graphopt layout. +* Testing strategy with subpackages are now CRAN and TRAVIS compatible. +* Test package `milne` created for unit testing of `InheritanceReporter`. +* Width of html reports adjust to size of screen. + +## BUG FIXES +* Rendering of the table in Function Network tab. + + \ No newline at end of file From a3be454dfadb3bdebcb6c6b60bc4a49d759eb0c4 Mon Sep 17 00:00:00 2001 From: Brian Burns Date: Sun, 16 Dec 2018 20:53:13 -0600 Subject: [PATCH 03/18] draft CRAN message --- cran-comments.md | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/cran-comments.md b/cran-comments.md index b2484669..a1fa4432 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,30 +1,52 @@ # CRAN Submission History -## v 0.2.1 - Submission 3 - (November 1st, 2018) +## v 0.3.0 + +### Upcoming submission [ETA December 19th, 2018] + +#### Message +This is a major release with several improvements to R package diagnostics, report layout, and testing strategy. New features and changes are now being tracked in NEWS.md. + + +--- + +## v 0.2.1 + +### Submission on November 1st, 2018 This is a minor release to address a bug with the `report_path` parameter of `CreatePackageReport`. Prior to this fix, reports would continue to be saved to a default location rather than the file path supplied by the user. Other items in this release are typo corrections, some additional parameter checks, and more verbose error and info messages. -## v 0.2.0 - Submission 2 - (April 30th, 2018) +--- + +## v 0.2.0 + +### Submission on April 30th, 2018 * Resubmitted to CRAN without test folder or source vigette code. * This was to ensure nothing is written outside of the temp folder during vignette build or package testing. * Future versions will handle this issue more directly. -## v0.1.0 - Submission 1 - (April 11, 2018) +---- + +## v0.1.0 -### R CMD check results +### Submission on April 12, 2018 + +#### R CMD check results +* No issues + +#### CRAN Response +* accepted and available on CRAN + +### Submission on April 11, 2018 + +#### R CMD check results * One NOTE about license file, will see what they say -### CRAN Response +#### CRAN Response * Need to use CRAN recognized LICENSE format * Need to single-quote `pkgnet` in `DESCRIPTION` file -## v0.1.0 - Submission 2 - (April 12, 2018) - -### R CMD check results -* No issues -### CRAN Response -* accepted and available on CRAN From 82ffd7d2b1ea1ea823a924c499841448f430d1e9 Mon Sep 17 00:00:00 2001 From: bburns632 Date: Mon, 17 Dec 2018 13:14:07 -0600 Subject: [PATCH 04/18] Update NEWS.md --- NEWS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1f91e9a8..2cf0352c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,7 @@ # Version 0.3.0 ## NEW FEATURES -* `InheritanceReporter`, a reporter to surface the R6 or S4 relationships within a package. +* InheritanceReporter, a reporter for R6, Reference, and S4 class inheritance relationships within a package. * Dropdown menu in graph visualizations for node selection. ## CHANGES @@ -15,4 +15,4 @@ ## BUG FIXES * Rendering of the table in Function Network tab. - \ No newline at end of file + From 9970185310ef0858ca237c3513352fc9c46a1b3c Mon Sep 17 00:00:00 2001 From: bburns632 Date: Mon, 17 Dec 2018 13:18:39 -0600 Subject: [PATCH 05/18] author edits and additions Addressed comments. --- NEWS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2cf0352c..7c2255bc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,12 +5,16 @@ * Dropdown menu in graph visualizations for node selection. ## CHANGES -* Edge direction reversed to align with UML class diagram convention. +* Edge direction reversed to align with UML class diagram convention. Now, if A depends on B, then A->B. * Default node colors are now colorblind accessible. * Function network design utilizes graphopt layout. +* Reporters now support all layouts available in igraph. Use grep("^layout_\\S", getNamespaceExports("igraph"), value = TRUE) to see valid options. +* `FunctionReporter` now supports non-exported functions and R6 class methods. * Testing strategy with subpackages are now CRAN and TRAVIS compatible. -* Test package `milne` created for unit testing of `InheritanceReporter`. +* Test package `milne` created for unit testing of `InheritanceReporter` and R6 method support in `FunctionReporter`. * Width of html reports adjust to size of screen. +* Orphaned node clustering was removed in favor of using layout to better handle graphs with many orphaned nodes. +* Various misc. improvements to UX for package reports. ## BUG FIXES * Rendering of the table in Function Network tab. From 4fc026e8e14b497f1f483263013d059fec5a6500 Mon Sep 17 00:00:00 2001 From: Jay Qi Date: Mon, 17 Dec 2018 21:38:21 -0600 Subject: [PATCH 06/18] NEWS.md v0.3.0 polish, and links to issues and PRs --- NEWS.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/NEWS.md b/NEWS.md index 7c2255bc..1787eb42 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,22 +1,22 @@ # Version 0.3.0 ## NEW FEATURES -* InheritanceReporter, a reporter for R6, Reference, and S4 class inheritance relationships within a package. -* Dropdown menu in graph visualizations for node selection. +* `InheritanceReporter`, a reporter for R6, Reference, and S4 class inheritance relationships within a package. ([#14](https://github.com/UptakeOpenSource/pkgnet/issues/14), [#129](https://github.com/UptakeOpenSource/pkgnet/pull/129)) +* Dropdown menu in graph visualizations for selecting which node to highlight. ([#132](https://github.com/UptakeOpenSource/pkgnet/issues/132), [#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) ## CHANGES -* Edge direction reversed to align with UML class diagram convention. Now, if A depends on B, then A->B. -* Default node colors are now colorblind accessible. -* Function network design utilizes graphopt layout. -* Reporters now support all layouts available in igraph. Use grep("^layout_\\S", getNamespaceExports("igraph"), value = TRUE) to see valid options. -* `FunctionReporter` now supports non-exported functions and R6 class methods. -* Testing strategy with subpackages are now CRAN and TRAVIS compatible. -* Test package `milne` created for unit testing of `InheritanceReporter` and R6 method support in `FunctionReporter`. -* Width of html reports adjust to size of screen. -* Orphaned node clustering was removed in favor of using layout to better handle graphs with many orphaned nodes. -* Various misc. improvements to UX for package reports. +* Edge direction reversed to align with [UML dependency diagram](https://en.wikipedia.org/wiki/Dependency_(UML)) convention. Now, if A depends on B, then A->B. ([#131](https://github.com/UptakeOpenSource/pkgnet/issues/131), [#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) +* Reporters now support all layouts available in igraph. Use `grep("^layout_\\S", getNamespaceExports("igraph"), value = TRUE)` to see valid options. ([#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) +* `FunctionReporter` now utilizes graphopt layout by default. ([#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) +* `FunctionReporter` now supports non-exported functions and R6 class methods. ([#123](https://github.com/UptakeOpenSource/pkgnet/issues/123), [#128](https://github.com/UptakeOpenSource/pkgnet/pull/128)) +* Orphaned node clustering was removed in favor of using layout to better handle graphs with many orphaned nodes. ([#102](https://github.com/UptakeOpenSource/pkgnet/issues/102), [#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) +* Testing strategy with subpackages are now CRAN and TRAVIS compatible. ([#121](https://github.com/UptakeOpenSource/pkgnet/issues/121), [#139](https://github.com/UptakeOpenSource/pkgnet/pull/139), [#144](https://github.com/UptakeOpenSource/pkgnet/pull/144)) +* Test package `milne` created for unit testing of `InheritanceReporter` and R6 method support in `FunctionReporter`. ([#128](https://github.com/UptakeOpenSource/pkgnet/issues/128), [#129](https://github.com/UptakeOpenSource/pkgnet/pull/129)) +* Width of html reports now adjust to size of screen. ([#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) +* Default node colors are now colorblind accessible. ([#130](https://github.com/UptakeOpenSource/pkgnet/issues/130), [#141](https://github.com/UptakeOpenSource/pkgnet/pull/141)) +* Additional various improvements to UX for package reports. ([#143](https://github.com/UptakeOpenSource/pkgnet/pull/143)) ## BUG FIXES -* Rendering of the table in Function Network tab. +* Rendering of the table in Function Network tab. ([#136](https://github.com/UptakeOpenSource/pkgnet/issues/136), [#138](https://github.com/UptakeOpenSource/pkgnet/pull/138)) From d1f17eac3d25afb55e36251e30d394082aa1945c Mon Sep 17 00:00:00 2001 From: Brian Burns Date: Tue, 18 Dec 2018 17:05:47 -0600 Subject: [PATCH 07/18] changes for pkgdown rendering --- NEWS.md | 2 +- _pkgdown.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 1787eb42..54e1a934 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# Version 0.3.0 +# pkgnet 0.3.0 ## NEW FEATURES * `InheritanceReporter`, a reporter for R6, Reference, and S4 class inheritance relationships within a package. ([#14](https://github.com/UptakeOpenSource/pkgnet/issues/14), [#129](https://github.com/UptakeOpenSource/pkgnet/pull/129)) diff --git a/_pkgdown.yml b/_pkgdown.yml index 2ade71e7..52c25cc1 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -12,6 +12,8 @@ navbar: href: reference/index.html - text: "Articles" href: articles/index.html + - text: "News" + href: news/index.html right: - icon: fa-github From 1f7aa7dd0e599da4fe1b09958e7ffdab8bdc07d6 Mon Sep 17 00:00:00 2001 From: Brian Burns Date: Wed, 19 Dec 2018 17:50:52 -0600 Subject: [PATCH 08/18] ignore readme_figures --- .Rbuildignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.Rbuildignore b/.Rbuildignore index bfa5b886..3e1b2336 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -50,6 +50,10 @@ vignettes/*\.pdf ^lib$ ^coverage.html$ +# Readme files +^readme_figures/.* + # Stuff .Rbuildignore .*\.gitkeep + From e9c2254eac16ad1ce245ddc071c1a9e5c90b3ccc Mon Sep 17 00:00:00 2001 From: Brian Burns Date: Wed, 19 Dec 2018 17:54:11 -0600 Subject: [PATCH 09/18] pkgdown website docs update --- docs/CONDUCT.html | 40 +- docs/CONTRIBUTING.html | 123 +- docs/LICENSE-text.html | 38 +- docs/LICENSE.html | 137 - docs/README.html | 169 - docs/articles/index.html | 40 +- docs/articles/pkgnet-intro.html | 5721 +---------------- .../htmlwidgets.js | 5 +- .../pkgnet-intro_files/vis-4.20.1/vis.css | 16 +- .../visNetwork.js | 585 +- docs/authors.html | 40 +- docs/cran-comments.html | 109 - docs/docsearch.css | 148 + docs/docsearch.js | 85 + docs/extra.css | 75 - docs/extra.js | 17 - docs/index.html | 60 +- docs/jquery.sticky-kit.min.js | 9 - docs/news/index.html | 174 + docs/pkgdown.css | 25 +- docs/pkgdown.js | 170 +- docs/pkgdown.yml | 6 +- docs/reference/AbstractGraphReporter.html | 49 +- docs/reference/AbstractPackageReporter.html | 43 +- docs/reference/CalcNetworkFeatures.html | 136 - docs/reference/CreatePackageReport.html | 49 +- docs/reference/DefaultReporters.html | 43 +- docs/reference/DependencyReporter.html | 50 +- docs/reference/ExtractDependencyNetwork.html | 156 - docs/reference/ExtractFunctionNetwork.html | 155 - docs/reference/ExtractNetwork.html | 155 - docs/reference/FunctionReporter.html | 77 +- docs/reference/GetCoverageByFunction.html | 126 - docs/reference/GetPackageGraphs.html | 154 - docs/reference/InheritanceReporter.html | 228 + docs/reference/MakeGraphObject.html | 133 - docs/reference/PackageDependencyReporter.html | 160 - docs/reference/PackageFunctionReporter.html | 169 - docs/reference/PackageSummaryReporter.html | 169 - docs/reference/PlotNetwork.html | 148 - docs/reference/RenderPackageReport.html | 140 - docs/reference/SummaryReporter.html | 50 +- docs/reference/doc_shared.html | 43 +- docs/reference/index.html | 59 +- 44 files changed, 2039 insertions(+), 8245 deletions(-) delete mode 100644 docs/LICENSE.html delete mode 100644 docs/README.html rename docs/articles/pkgnet-intro_files/{htmlwidgets-0.9 => htmlwidgets-1.3}/htmlwidgets.js (99%) rename docs/articles/pkgnet-intro_files/{visNetwork-binding-2.0.3 => visNetwork-binding-2.0.5}/visNetwork.js (84%) delete mode 100644 docs/cran-comments.html create mode 100644 docs/docsearch.css create mode 100644 docs/docsearch.js delete mode 100644 docs/extra.css delete mode 100644 docs/extra.js delete mode 100644 docs/jquery.sticky-kit.min.js create mode 100644 docs/news/index.html delete mode 100644 docs/reference/CalcNetworkFeatures.html delete mode 100644 docs/reference/ExtractDependencyNetwork.html delete mode 100644 docs/reference/ExtractFunctionNetwork.html delete mode 100644 docs/reference/ExtractNetwork.html delete mode 100644 docs/reference/GetCoverageByFunction.html delete mode 100644 docs/reference/GetPackageGraphs.html create mode 100644 docs/reference/InheritanceReporter.html delete mode 100644 docs/reference/MakeGraphObject.html delete mode 100644 docs/reference/PackageDependencyReporter.html delete mode 100644 docs/reference/PackageFunctionReporter.html delete mode 100644 docs/reference/PackageSummaryReporter.html delete mode 100644 docs/reference/PlotNetwork.html delete mode 100644 docs/reference/RenderPackageReport.html diff --git a/docs/CONDUCT.html b/docs/CONDUCT.html index 1ca8fc65..219b96e7 100644 --- a/docs/CONDUCT.html +++ b/docs/CONDUCT.html @@ -1,6 +1,6 @@ - + @@ -9,27 +9,34 @@ Contributor Covenant Code of Conduct • pkgnet - + - + - + - + - + + + + - + + + + - + + - - @@ -47,14 +52,15 @@

- -Running pkgnet -

-

-pkgnet can analyze any R package locally installed. Run installed.packages() to see the full list of packages installed on your system. For this example, let’s say we are analyzing a custom built package, baseballstats. -

-

-To analyze baseballstats, run the following two lines of code: -

-
-
library(pkgnet)
-report1 <- CreatePackageReport(pkg_name = "baseballstats")
-
-

-That’s it! You have generated a lot of valuable information with that one call for an installed package. -

-

-However, if the full source repository for the package is available on your system, you can supplement this report with other information such as code coverage from covr. To do so, specify the path to the repository in CreatePackageReport. -

- +Running pkgnet +

pkgnet can analyze any R package locally installed. (Run installed.packages() to see the full list of packages installed on your system.) For this example, let’s say we are analyzing a custom built package, baseballstats.

+

To analyze baseballstats, run the following two lines of code:

+
library(pkgnet)
+report1 <- CreatePackageReport(pkg_name = "baseballstats")
+

That’s it! You have generated a lot of valuable information with that one call for an installed package.

+

However, if the full source repository for the package is available on your system, you can supplement this report with other information such as code coverage from covr. To do so, specify the path to the repository in CreatePackageReport.

+

- -Examining The Results -

-

-An HTML report has been created with the pertinent information and a list object is available with the same information and more. -

+Examining the Results +

CreatePackageReport has written an HTML report with the pertinent information, and it also returned a list object with the same information and more.

- -The Report -

-

-An HTML report has been created, and its location is specified in the messages in the terminal. -

-

-This report has three sections: -

+The Report +

The location of the HTML report is specified in the messages in the terminal.

+

This report has three sections:

  1. -Package Summary – general information about the package and package level statistics
    -
  2. +Package Summary – general information about the package and package level statistics
  3. -Dependency Network – information regarding the packages upon which the current package under analysis relies upon
    -
  4. +Dependency Network – information regarding the packages upon which the current package under analysis depends upon
  5. -Function Network – information regarding the functions within the current package under analysis and their inter dependencies -
  6. +Function Network – information regarding the functions within the current package under analysis and their interdependencies
-

-Each section has helpful tables and visuals. -

-

-As a sample, here’s how the Function Network Visualization looks for baseballstats: -

+

Each section has helpful tables and visuals.

+

As a sample, here’s how the Function Network Visualization looks for baseballstats:

-

- -

+

-

-Default -

-

-

-
- -
- -All Functions and their dependencies are visible. For example, we can see that both batting_avg and slugging_avg functions depend upon the at_bats function. - -

-We also see that nothing depends on the on_base_pct function. This might be valuable information to an R package developer. -

+

Default

+

+
+ All functions and their dependencies are visible. For example, we can see that both batting_avg and slugging_avg functions depend upon the at_bats function. +

We also see that nothing depends on the on_base_pct function. This might be valuable information to an R package developer.

-

- -

+

-

-With Coverage Information -

-

-

-
- +

With Coverage Information

+

+
+ Same as the default visualization except we can see coverage information as well (Pink = 0%, Green = 100%). +

It appears the function with the most dependencies, at_bats, is well covered. However, no other functions are covered by unit tests.

- -Same as the default visualization except we can see coverage information as well (Red = 0%, Green = 100%). - -

-It appears the function with the most dependencies, at_bats, is well covered. However, no other functions are covered by unit tests. -

-
-

- -

+

-

- - -

-

-Check out the full HTML report for more results -

+

+

Check out the full HTML report for more results

- -The List Object -

-

-The CreatePackageReport() function returns a list with three items: -

+The List Object +

The CreatePackageReport() function returns a list with three items:

    -
  1. -SummaryReporter
    +
  2. SummaryReporter
  3. -
  4. -DependencyReporter
    -
  5. -
  6. -FunctionReporter +
  7. DependencyReporter
  8. +
  9. FunctionReporter
-

-Each items contains information visible in the report and more. We can use this information for a more detailed analysis of the results and/or more easily incorporate pkgnet results into other R processes. -

-

-Here are a few notable items available within the list object. -

+

Each items contains information visible in the report and more. We can use this information for a more detailed analysis of the results and/or more easily incorporate pkgnet results into other R processes.

+

Here are a few notable items available within the list object:

- -Node Information -

-

-Both the DependencyReporter and the FunctionReporter contain metrics about their package dependencies or functions (a.k.a network nodes) in a nodes table. -

- -
#> [1]  5 13
- -
#>  [1] "node"                "coveredLines"        "totalLines"         
-#>  [4] "coverageRatio"       "meanCoveragePerLine" "filename"           
-#>  [7] "outDegree"           "outBetweeness"       "outCloseness"       
-#> [10] "numDescendants"      "hubScore"            "pageRank"           
-#> [13] "inDegree"
-

-Note, a few of these metrics provided by default are from the field of Network Theory. You can leverage the Network Object described below to derive many more. -

+Node Information +

Both the DependencyReporter and the FunctionReporter contain metrics about their package dependencies or functions (a.k.a network nodes) in a nodes table.

+
dim(report2$FunctionReporter$nodes)
+
#> [1]  5 16
+
names(report2$FunctionReporter$nodes)
+
#>  [1] "node"                "type"                "isExported"         
+#>  [4] "coveredLines"        "totalLines"          "coverageRatio"      
+#>  [7] "meanCoveragePerLine" "filename"            "outDegree"          
+#> [10] "outBetweeness"       "outCloseness"        "outSubgraphSize"    
+#> [13] "inSubgraphSize"      "hubScore"            "pageRank"           
+#> [16] "inDegree"
+

Note, a few of these metrics provided by default are from the field of Network Theory. You can leverage the Network Object described below to derive many more.

- -Network Measures -

-

-Both the DependencyReporter and the FunctionReporter contain measures based on their network structure in a network_measures list. -

- +Network Measures +

Both the DependencyReporter and the FunctionReporter contain graph-level measures based on their network structure in a network_measures list.

+
#> $centralization.OutDegree
 #> [1] 0.3
 #> 
@@ -5343,282 +235,168 @@ 

#> [1] 0.03125 #> #> $centralization.closeness -#> [1] 0.2743056

+#> [1] 0.2743056 +#> +#> $packageTestCoverage.mean +#> [1] 0.1 +#> +#> $packageTestCoverage.betweenessWeightedMean +#> [1] 0.5

- -Network Object -

-

-Both the DependencyReporter and the FunctionReporter are available as igraph objects named pkg_graph -

- -
#> IGRAPH 668bfff DN-- 5 4 -- 
+Network Object
+

Both the DependencyReporter and the FunctionReporter are available as igraph objects named pkg_graph

+ +
#> IGRAPH ec3068d DN-- 5 4 -- 
 #> + attr: name (v/c)
-#> + edges from 668bfff (vertex names):
-#> [1] at_bats     ->batting_avg  at_bats     ->slugging_avg
-#> [3] batting_avg ->OPS          slugging_avg->OPS
+#> + edges from ec3068d (vertex names): +#> [1] OPS ->slugging_avg OPS ->batting_avg +#> [3] slugging_avg->at_bats batting_avg ->at_bats

- -A Deeper Look -

-

-With the reports and objects produced by pkgnet by default, there is plenty to inform us on the inner workings of an R package. However, we may want to know MORE! Since the igraph objects are available, we can leverage those graphs for further analysis. -

-

-In this section, let’s examine a larger R package, such as lubridate. -

-

-If you would like to follow along with the examples in this section, run these commands in your terminal to download and install lubridate1. -

- -
+A Deeper Look +

With the reports and objects produced by pkgnet by default, there is plenty to inform us on the inner workings of an R package. However, we may want to know MORE! Since the igraph objects are available, we can leverage those graphs for further analysis.

+

In this section, let’s examine a larger R package, such as lubridate.

+

If you would like to follow along with the examples in this section, run these commands in your terminal to download and install lubridate2.

+ +

- -Coverage of Most Referenced Functions -

-

-Let’s examine the relationship between a function’s total number of descendants and the unit test coverage of that function’s code. -

+Coverage of Most Depended-on Functions +

Let’s examine lubridate’s functions through the lens of each function’s total number of dependents (i.e., the other functions that depend on it) and its code’s unit test coverage. In our graph model for the FunctionReporter, the subgraph of paths leading into a given node is the set of functions that directly or indirectly depend on the function that node represents.

- + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + +
-Function - -Descendant Count - -Coverage Ratio - -Total Lines -FunctionIn-Subgraph SizeCoverage RatioTotal Lines
-divide_period_by_period - -39 - -1 - -2 -divide_period_by_period3912
-days - -22 - -1 - -1 -days2211
-check_duration - -15 - -0 - -1 -check_duration1501
-as.POSIXt - -13 - -0 - -1 -as.POSIXt1301
-eweeks - -13 - -0 - -2 -eweeks1302
-check_interval - -12 - -0 - -11 -check_interval12011
-date<- - -12 - -NA - -NA -date<-12NANA
-add_months - -10 - -1 - -4 -add_months1014
-ceil_multi_unit - -10 - -1 - -1 -ceil_multi_unit1011
-am - -6 - -1 - -1 -am611
-

-Inspecting results such as these can help an R package developer decide which function to cover with unit tests next. -

-

-In this case, check_duration, one of the most referenced functions (either directly or indirectly), is not covered by unit tests. However, it appears to be a simple one line function that may not be necessary to cover in unit testing. check_interval, on the other hand, might benefit from some unit test coverage as it is a larger, uncovered function with a similar number of dependencies. -

+

Inspecting results such as these can help an R package developer decide which function to cover with unit tests next.

+

In this case, check_duration, one of the most depended-on functions (either directly or indirectly), is not covered by unit tests. However, it appears to be a simple one line function that may not be necessary to cover in unit testing. check_interval, on the other hand, might benefit from some unit test coverage as it is a larger, uncovered function with a similar number of dependencies.

- -Discovering Similar Functions -

-

-Looking at that same large package, let’s say we wanted to explore options for consolidating functions. One approach might be to explore consolidating functions that share the same dependencies. In that case, we could use the igraph object to highlight functions with the same dependencies via Jaccard similarity. -

- +Discovering Similar Functions +

Looking at that same large package, let’s say we want to explore options for consolidating functions. One approach might be to explore consolidating functions that share the same dependencies. In that case, we could use the igraph object to highlight functions with the same out-neighborhood via Jaccard similarity.

+
#> Group 1: stamp_time, stamp_date
 #> Group 2: ms, hm
 #> Group 3: new_interval, %--%, int_diff
@@ -5626,46 +404,55 @@ 

#> Group 5: picoseconds, microseconds, nanoseconds, milliseconds #> Group 6: weeks, days, years, seconds_to_period, seconds, new_period, minutes, hours #> Group 7: yq, dmy, ymd_hms, ymd_hm, ymd_h, ymd, ydm_hms, ydm_hm, ydm_h, ydm, pretty_dates, parse_date_time2, parse_date_time, myd, mdy_hms, mdy_hm, mdy_h, mdy, local_time, fast_strptime, dym, dmy_hms, dmy_hm, dmy_h

-

-Now, we have identified seven different groups of functions within lubridate that share the exact same dependencies. We could explore each group of functions for potential consolidation. -

+

Now, we have identified seven different groups of functions within lubridate that share the exact same dependencies. We could explore each group of functions for potential consolidation.


    -
  1. -

    -Examples from version 1.7.3 of Lubridate -

    -
  2. +
  3. Edge direction was previously Independent -> Dependent. It was changed to Dependent -> Independent in version v0.3.0. The new convention follows the Unified Modeling Language (UML) framework, a widely used standard for software system modeling.

  4. +
  5. Examples from version 1.7.3 of Lubridate

- - -
+
-

Site built with pkgdown.

+

Site built with pkgdown 1.3.0.

-
diff --git a/docs/articles/pkgnet-intro_files/htmlwidgets-0.9/htmlwidgets.js b/docs/articles/pkgnet-intro_files/htmlwidgets-1.3/htmlwidgets.js similarity index 99% rename from docs/articles/pkgnet-intro_files/htmlwidgets-0.9/htmlwidgets.js rename to docs/articles/pkgnet-intro_files/htmlwidgets-1.3/htmlwidgets.js index ecda3ef8..ed9837d9 100644 --- a/docs/articles/pkgnet-intro_files/htmlwidgets-0.9/htmlwidgets.js +++ b/docs/articles/pkgnet-intro_files/htmlwidgets-1.3/htmlwidgets.js @@ -565,7 +565,10 @@ } if (binding.resize) { - var lastSize = {}; + var lastSize = { + w: sizeObj ? sizeObj.getWidth() : el.offsetWidth, + h: sizeObj ? sizeObj.getHeight() : el.offsetHeight + }; var resizeHandler = function(e) { var size = { w: sizeObj ? sizeObj.getWidth() : el.offsetWidth, diff --git a/docs/articles/pkgnet-intro_files/vis-4.20.1/vis.css b/docs/articles/pkgnet-intro_files/vis-4.20.1/vis.css index 7b0217c1..c2f3e1a6 100644 --- a/docs/articles/pkgnet-intro_files/vis-4.20.1/vis.css +++ b/docs/articles/pkgnet-intro_files/vis-4.20.1/vis.css @@ -1,12 +1,16 @@ -.rPartvisNetworkTooltipShowme{ +.classActivePointer:hover { + cursor: pointer; +} + +/*.rPartvisNetworkTooltipShowme{ display: none; } .rPartvisNetworkTooltipShowhim:hover .rPartvisNetworkTooltipShowme{ display : block; -} +}*/ -hr.rPartvisNetwork{ - margin: 0.1em auto; +.rPartvisNetwork{ + margin: 0.5em auto; } .vis .overlay { @@ -319,7 +323,7 @@ input.vis-configuration.vis-config-range:focus::-ms-fill-upper { border-width: 12px; margin-top: -12px; } -/* + div.vis-tooltip { position: absolute; visibility: hidden; @@ -341,7 +345,7 @@ div.vis-tooltip { z-index: 5; } -*/ + div.vis-color-picker { position:absolute; diff --git a/docs/articles/pkgnet-intro_files/visNetwork-binding-2.0.3/visNetwork.js b/docs/articles/pkgnet-intro_files/visNetwork-binding-2.0.5/visNetwork.js similarity index 84% rename from docs/articles/pkgnet-intro_files/visNetwork-binding-2.0.3/visNetwork.js rename to docs/articles/pkgnet-intro_files/visNetwork-binding-2.0.5/visNetwork.js index ef08b7ff..e85b1fb3 100644 --- a/docs/articles/pkgnet-intro_files/visNetwork-binding-2.0.3/visNetwork.js +++ b/docs/articles/pkgnet-intro_files/visNetwork-binding-2.0.5/visNetwork.js @@ -1,3 +1,134 @@ +// Production steps of ECMA-262, Edition 6, 22.1.2.1 +// Référence : https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from +if (!Array.from) { + Array.from = (function () { + var toStr = Object.prototype.toString; + var isCallable = function (fn) { + return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; + }; + var toInteger = function (value) { + var number = Number(value); + if (isNaN(number)) { return 0; } + if (number === 0 || !isFinite(number)) { return number; } + return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); + }; + var maxSafeInteger = Math.pow(2, 53) - 1; + var toLength = function (value) { + var len = toInteger(value); + return Math.min(Math.max(len, 0), maxSafeInteger); + }; + + // La propriété length de la méthode vaut 1. + return function from(arrayLike/*, mapFn, thisArg */) { + // 1. Soit C, la valeur this + var C = this; + + // 2. Soit items le ToObject(arrayLike). + var items = Object(arrayLike); + + // 3. ReturnIfAbrupt(items). + if (arrayLike == null) { + throw new TypeError("Array.from doit utiliser un objet semblable à un tableau - null ou undefined ne peuvent pas être utilisés"); + } + + // 4. Si mapfn est undefined, le mapping sera false. + var mapFn = arguments.length > 1 ? arguments[1] : void undefined; + var T; + if (typeof mapFn !== 'undefined') { + // 5. sinon + // 5. a. si IsCallable(mapfn) est false, on lève une TypeError. + if (!isCallable(mapFn)) { + throw new TypeError('Array.from: lorsqu il est utilisé le deuxième argument doit être une fonction'); + } + + // 5. b. si thisArg a été fourni, T sera thisArg ; sinon T sera undefined. + if (arguments.length > 2) { + T = arguments[2]; + } + } + + // 10. Soit lenValue pour Get(items, "length"). + // 11. Soit len pour ToLength(lenValue). + var len = toLength(items.length); + + // 13. Si IsConstructor(C) vaut true, alors + // 13. a. Soit A le résultat de l'appel à la méthode interne [[Construct]] avec une liste en argument qui contient l'élément len. + // 14. a. Sinon, soit A le résultat de ArrayCreate(len). + var A = isCallable(C) ? Object(new C(len)) : new Array(len); + + // 16. Soit k égal à 0. + var k = 0; // 17. On répète tant que k < len… + var kValue; + while (k < len) { + kValue = items[k]; + if (mapFn) { + A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); + } else { + A[k] = kValue; + } + k += 1; + } + // 18. Soit putStatus égal à Put(A, "length", len, true). + A.length = len; // 20. On renvoie A. + return A; + }; + }()); +}; + + +// https://tc39.github.io/ecma262/#sec-array.prototype.includes +if (!Array.prototype.includes) { + Object.defineProperty(Array.prototype, 'includes', { + value: function(searchElement, fromIndex) { + + if (this == null) { + throw new TypeError('"this" est nul ou non défini'); + } + + // 1. Soit o égal à ? Object(cette valeur). + var o = Object(this); + + // 2. Soit len égal à ? Length(? Get(o, "length")). + var len = o.length >>> 0; + + // 3. Si len = 0, renvoyer "false". + if (len === 0) { + return false; + } + + // 4. Soit n = ? ToInteger(fromIndex). + // Pour la cohérence du code, on gardera le nom anglais "fromIndex" pour la variable auparavant appelée "indiceDépart" + // (Si fromIndex n'est pas défini, cette étape produit la valeur 0.) + var n = fromIndex | 0; + + // 5. Si n ≥ 0, + // a. Alors k = n. + // 6. Sinon, si n < 0, + // a. Alors k = len + n. + // b. Si k < 0, alors k = 0. + var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); + + function sameValueZero(x, y) { + return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); + } + + // 7. Répéter tant que k < len + while (k < len) { + // a. Soit elementK le résultat de ? Get(O, ! ToString(k)). + // b. Si SameValueZero(searchElement, elementK) est vrai, renvoyer "true". + if (sameValueZero(o[k], searchElement)) { + return true; + } + // c. Augmenter la valeur de k de 1. + k++; + } + + // 8. Renvoyer "false" + return false; + } + }); +} + // Add shim for Function.prototype.bind() from: // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility // for fix some RStudio viewer bug (Desktop / windows) @@ -59,7 +190,9 @@ function edgeAsHardToRead(edge, hideColor1, hideColor2, network, type){ //network.clustering.updateEdge(edge.id, {hiddenColor : edge.color}); edge.hiddenColor = edge.color; } - network.clustering.updateEdge(edge.id, {color : hideColor1}); + // set "hard to read" color + edge.color = hideColor1; + //network.clustering.updateEdge(edge.id, {color : hideColor1}); //edge.color = hideColor1; // reset and save label if (edge.hiddenLabel === undefined) { @@ -770,6 +903,12 @@ function uniqueArray(arr, exclude_cluster, network) { return a; } + +function uniqueShiny(arr) { + return arr.filter(function (value, index, self) { + return self.indexOf(value) === index; + }); +}; // clone an object function clone(obj) { if(obj === null || typeof(obj) != 'object') @@ -828,7 +967,12 @@ function setNodeIdList(selectList, params, nodes){ option = document.createElement("option"); option.value = ""; - option.text = "Select by id"; + if(params.main === undefined){ + option.text = "Select by id"; + } else { + option.text = params.main; + } + selectList.appendChild(option); // have to set for all nodes ? @@ -881,7 +1025,17 @@ function networkOpenCluster(params){ var elid = this.body.container.id.substring(5); var fit = document.getElementById(elid).collapseFit; var resetHighlight = document.getElementById(elid).collapseResetHighlight; - this.openCluster(params.nodes[0]); + + if(document.getElementById(elid).collapseKeepCoord){ + this.openCluster(params.nodes[0], + {releaseFunction : function(clusterPosition, containedNodesPositions) { + return containedNodesPositions; + } + }); + } else { + this.openCluster(params.nodes[0]); + } + if(resetHighlight){ document.getElementById("nodeSelect"+elid).value = ""; @@ -894,7 +1048,7 @@ function networkOpenCluster(params){ } } -function collapsedNetwork(nodes, fit, resetHighlight, clusterParams, treeParams, network, elid) { +function collapsedNetwork(nodes, fit, resetHighlight, clusterParams, labelSuffix, treeParams, network, elid) { var set_position = true; var selectedNode; @@ -1019,9 +1173,9 @@ function collapsedNetwork(nodes, fit, resetHighlight, clusterParams, treeParams, } if(clusterOptions.label !== undefined){ - clusterOptions.label = clusterOptions.label + ' (cluster)' + clusterOptions.label = clusterOptions.label + " " + labelSuffix; } else { - clusterOptions.label = '(cluster)' + clusterOptions.label = labelSuffix; } if(clusterOptions.borderWidth !== undefined){ @@ -1048,7 +1202,7 @@ function collapsedNetwork(nodes, fit, resetHighlight, clusterParams, treeParams, return clusterOptions; }, clusterNodeProperties: { - allowSingleNodeCluster: false, + allowSingleNodeCluster: false } } network.cluster(clusterOptions); @@ -1066,7 +1220,7 @@ function collapsedNetwork(nodes, fit, resetHighlight, clusterParams, treeParams, } }; -function uncollapsedNetwork(nodes, fit, resetHighlight, network, elid) { +function uncollapsedNetwork(nodes, fit, resetHighlight, keepCoord, network, elid) { var selectedNode; var j; var arr_nodes = []; @@ -1086,17 +1240,33 @@ function uncollapsedNetwork(nodes, fit, resetHighlight, network, elid) { } for (var inodes = 0; inodes < arr_nodes.length; inodes++) { - selectedNode = arr_nodes[inodes]; + selectedNode = '' + arr_nodes[inodes]; if(selectedNode !== undefined){ if(network.isCluster(selectedNode)){ - network.openCluster(selectedNode) + if(keepCoord){ + network.openCluster(selectedNode, + {releaseFunction : function(clusterPosition, containedNodesPositions) { + return containedNodesPositions; + } + }); + } else { + network.openCluster(selectedNode) + } } else { if(indexOf.call(nodes_in_clusters, selectedNode, true) > -1){ // not a cluster into a cluster... if(selectedNode.search(/^cluster/i) === -1){ cluster_node = network.clustering.findNode(selectedNode)[0]; if(network.isCluster(cluster_node)){ - network.openCluster(cluster_node) + if(keepCoord){ + network.openCluster(cluster_node, + {releaseFunction : function(clusterPosition, containedNodesPositions) { + return containedNodesPositions; + } + }); + } else { + network.openCluster(cluster_node) + } } } } @@ -1122,7 +1292,7 @@ if (HTMLWidgets.shinyMode){ // get container id var el = document.getElementById("graph"+data.id); if(el){ - collapsedNetwork(data.nodes, data.fit, data.resetHighlight, data.clusterOptions, undefined, el.chart, data.id) + collapsedNetwork(data.nodes, data.fit, data.resetHighlight, data.clusterOptions, data.labelSuffix, undefined, el.chart, data.id) } }); @@ -1131,7 +1301,7 @@ if (HTMLWidgets.shinyMode){ // get container id var el = document.getElementById("graph"+data.id); if(el){ - uncollapsedNetwork(data.nodes, data.fit, data.resetHighlight, el.chart, data.id) + uncollapsedNetwork(data.nodes, data.fit, data.resetHighlight, data.keepCoord, el.chart, data.id) } }); @@ -1192,6 +1362,7 @@ if (HTMLWidgets.shinyMode){ Shiny.addCustomMessageHandler('visShinyOptions', function(data){ // get container id var el = document.getElementById("graph"+data.id); + if(el){ var network = el.chart; var options = el.options; @@ -1207,6 +1378,34 @@ if (HTMLWidgets.shinyMode){ } } + //************************* + // pre-treatment for icons (unicode) + //************************* + if(data.options.groups){ + for (var gr in data.options.groups){ + if(data.options.groups[gr].icon){ + if(data.options.groups[gr].icon.code){ + data.options.groups[gr].icon.code = JSON.parse( '"'+'\\u' + data.options.groups[gr].icon.code + '"'); + } + if(data.options.groups[gr].icon.color){ + data.options.groups[gr].color = data.options.groups[gr].icon.color; + } + } + } + } + + if(data.options.nodes){ + if(data.options.nodes.icon){ + if(data.options.nodes.icon.code){ + data.options.nodes.icon.code = JSON.parse( '"'+'\\u' + data.options.nodes.icon.code + '"'); + } + if(data.options.nodes.icon.color){ + data.options.nodes.color = data.options.nodes.icon.color; + } + } + } + + update(options, data.options); network.setOptions(options); } @@ -1537,6 +1736,8 @@ if (HTMLWidgets.shinyMode){ el.collapse = data.options.collapse.enabled; el.collapseFit = data.options.collapse.fit; el.collapseResetHighlight = data.options.collapse.resetHighlight; + el.collapseKeepCoord = data.options.collapse.keepCoord; + el.collapseLabelSuffix = data.options.collapse.labelSuffix; el.clusterOptions = data.options.collapse.clusterOptions; } @@ -1567,7 +1768,12 @@ if (HTMLWidgets.shinyMode){ if(data.options.byselection.enabled === true){ option2 = document.createElement("option"); option2.value = ""; - option2.text = "Select by " + data.options.byselection.variable; + if(data.options.byselection.main === undefined){ + option2.text = "Select by " + data.options.byselection.variable; + } else { + option2.text = data.options.byselection.main; + } + selectList2.appendChild(option2); if(data.options.byselection.values !== undefined){ @@ -1635,6 +1841,7 @@ if (HTMLWidgets.shinyMode){ selectList.options.length = 0; if(data.options.idselection.enabled === true){ setNodeIdList(selectList, data.options.idselection, graph.nodes) + el.idselection = true; } else { selectList.style.display = 'none'; el.idselection = false; @@ -1668,7 +1875,9 @@ if (HTMLWidgets.shinyMode){ // reset some parameters / data before if (main_el.selectActive === true | main_el.highlightActive === true) { + //reset nodes + resetAllEdges(el.edges, el.highlightColor, el.byselectionColor, el.chart); resetAllNodes(el.nodes, true, el.chart.groups, el.options, el.chart); if (main_el.selectActive === true){ @@ -1910,14 +2119,16 @@ if (HTMLWidgets.shinyMode){ // get container id var el = document.getElementById(data.id); if(el){ - if(data.tree.updateShape != undefined){ - el.tree.updateShape = data.tree.updateShape - } - if(data.tree.shapeVar != undefined){ - el.tree.shapeVar = data.tree.shapeVar - } - if(data.tree.shapeY != undefined){ - el.tree.shapeY = data.tree.shapeY + if(el.tree){ + if(data.tree.updateShape != undefined){ + el.tree.updateShape = data.tree.updateShape + } + if(data.tree.shapeVar != undefined){ + el.tree.shapeVar = data.tree.shapeVar + } + if(data.tree.shapeY != undefined){ + el.tree.shapeY = data.tree.shapeY + } } } }); @@ -2001,12 +2212,16 @@ HTMLWidgets.widget({ el_id.collapse = true; el_id.collapseFit = x.collapse.fit; el_id.collapseResetHighlight = x.collapse.resetHighlight; + el_id.collapseKeepCoord = x.collapse.keepCoord; + el_id.collapseLabelSuffix = x.collapse.labelSuffix; el_id.clusterOptions = x.collapse.clusterOptions; } } else { el_id.collapse = false; el_id.collapseFit = false; el_id.collapseResetHighlight = false; + el_id.collapseKeepCoord = true; + el_id.collapseLabelSuffix = " (cluster)"; el_id.clusterOptions = undefined; } @@ -2151,7 +2366,12 @@ HTMLWidgets.widget({ option2 = document.createElement("option"); option2.value = ""; - option2.text = "Select by " + x.byselection.variable; + if(x.byselection.main === undefined){ + option2.text = "Select by " + x.byselection.variable; + } else { + option2.text = x.byselection.main; + } + selectList2.appendChild(option2); //Create and append the options @@ -2583,61 +2803,165 @@ HTMLWidgets.widget({ el_id.appendChild(div); - options.manipulation.addNode = function(data, callback) { - document.getElementById('operation').innerHTML = "Add Node"; - document.getElementById('node-id').value = data.id; - document.getElementById('node-label').value = data.label; - document.getElementById('saveButton').onclick = saveNode.bind(this, data, callback, "addNode"); - document.getElementById('cancelButton').onclick = clearPopUp.bind(); - document.getElementById('network-popUp').style.display = 'block'; - }; + if(x.options.manipulation.addNode === undefined){ + options.manipulation.addNode = function(data, callback) { + document.getElementById('operation').innerHTML = "Add Node"; + document.getElementById('node-id').value = data.id; + document.getElementById('node-label').value = data.label; + document.getElementById('saveButton').onclick = saveNode.bind(this, data, callback, "addNode"); + document.getElementById('cancelButton').onclick = clearPopUp.bind(); + document.getElementById('network-popUp').style.display = 'block'; + }; + } else if(typeof(x.options.manipulation.addNode) === typeof(true)){ + if(x.options.manipulation.addNode){ + options.manipulation.addNode = function(data, callback) { + document.getElementById('operation').innerHTML = "Add Node"; + document.getElementById('node-id').value = data.id; + document.getElementById('node-label').value = data.label; + document.getElementById('saveButton').onclick = saveNode.bind(this, data, callback, "addNode"); + document.getElementById('cancelButton').onclick = clearPopUp.bind(); + document.getElementById('network-popUp').style.display = 'block'; + }; + } else { + options.manipulation.addNode = false; + } + } else { + options.manipulation.addNode = x.options.manipulation.addNode; + } - options.manipulation.editNode = function(data, callback) { - document.getElementById('operation').innerHTML = "Edit Node"; - document.getElementById('node-id').value = data.id; - document.getElementById('node-label').value = data.label; - document.getElementById('saveButton').onclick = saveNode.bind(this, data, callback, "editNode"); - document.getElementById('cancelButton').onclick = cancelEdit.bind(this,callback); - document.getElementById('network-popUp').style.display = 'block'; - }; + if(x.options.manipulation.editNode === undefined){ + options.manipulation.editNode = function(data, callback) { + document.getElementById('operation').innerHTML = "Edit Node"; + document.getElementById('node-id').value = data.id; + document.getElementById('node-label').value = data.label; + document.getElementById('saveButton').onclick = saveNode.bind(this, data, callback, "editNode"); + document.getElementById('cancelButton').onclick = cancelEdit.bind(this,callback); + document.getElementById('network-popUp').style.display = 'block'; + }; + } else if(typeof(x.options.manipulation.editNode) === typeof(true)){ + if(x.options.manipulation.editNode){ + options.manipulation.editNode = function(data, callback) { + document.getElementById('operation').innerHTML = "Edit Node"; + document.getElementById('node-id').value = data.id; + document.getElementById('node-label').value = data.label; + document.getElementById('saveButton').onclick = saveNode.bind(this, data, callback, "editNode"); + document.getElementById('cancelButton').onclick = cancelEdit.bind(this,callback); + document.getElementById('network-popUp').style.display = 'block'; + }; + } else { + options.manipulation.editNode = false; + } + } else { + options.manipulation.editNode = x.options.manipulation.editNode; + } + + if(x.options.manipulation.deleteNode === undefined){ + options.manipulation.deleteNode = function(data, callback) { + var r = confirm("Do you want to delete " + data.nodes.length + " node(s) and " + data.edges.length + " edges ?"); + if (r === true) { + deleteSubGraph(data, callback); + } + }; + } else if(typeof(x.options.manipulation.deleteNode) === typeof(true)){ + if(x.options.manipulation.deleteNode){ + options.manipulation.deleteNode = function(data, callback) { + var r = confirm("Do you want to delete " + data.nodes.length + " node(s) and " + data.edges.length + " edges ?"); + if (r === true) { + deleteSubGraph(data, callback); + } + }; + } else { + options.manipulation.deleteNode = false; + } + } else { + options.manipulation.deleteNode = x.options.manipulation.deleteNode; + } - options.manipulation.deleteNode = function(data, callback) { - var r = confirm("Do you want to delete " + data.nodes.length + " node(s) and " + data.edges.length + " edges ?"); - if (r === true) { - deleteSubGraph(data, callback); - } - }; + if(x.options.manipulation.deleteEdge === undefined){ + options.manipulation.deleteEdge = function(data, callback) { + var r = confirm("Do you want to delete " + data.edges.length + " edges ?"); + if (r === true) { + deleteSubGraph(data, callback); + } + }; + } else if(typeof(x.options.manipulation.deleteEdge) === typeof(true)){ + if(x.options.manipulation.deleteEdge){ + options.manipulation.deleteEdge = function(data, callback) { + var r = confirm("Do you want to delete " + data.edges.length + " edges ?"); + if (r === true) { + deleteSubGraph(data, callback); + } + }; + } else { + options.manipulation.deleteEdge = false; + } + } else { + options.manipulation.deleteEdge = x.options.manipulation.deleteEdge; + } - options.manipulation.deleteEdge = function(data, callback) { - var r = confirm("Do you want to delete " + data.edges.length + " edges ?"); - if (r === true) { - deleteSubGraph(data, callback); + if(x.options.manipulation.addEdge === undefined){ + options.manipulation.addEdge = function(data, callback) { + if (data.from == data.to) { + var r = confirm("Do you want to connect the node to itself?"); + if (r === true) { + saveEdge(data, callback, "addEdge"); + } } - }; - - options.manipulation.addEdge = function(data, callback) { - if (data.from == data.to) { - var r = confirm("Do you want to connect the node to itself?"); - if (r === true) { + else { saveEdge(data, callback, "addEdge"); } + }; + } else if(typeof(x.options.manipulation.addEdge) === typeof(true)){ + if(x.options.manipulation.addEdge){ + options.manipulation.addEdge = function(data, callback) { + if (data.from == data.to) { + var r = confirm("Do you want to connect the node to itself?"); + if (r === true) { + saveEdge(data, callback, "addEdge"); + } + } + else { + saveEdge(data, callback, "addEdge"); + } + }; + } else { + options.manipulation.addEdge = false; } - else { - saveEdge(data, callback, "addEdge"); - } - }; - - options.manipulation.editEdge = function(data, callback) { - if (data.from == data.to) { - var r = confirm("Do you want to connect the node to itself?"); - if (r === true) { + } else { + options.manipulation.addEdge = x.options.manipulation.addEdge; + } + + if(x.options.manipulation.editEdge === undefined){ + options.manipulation.editEdge = function(data, callback) { + if (data.from == data.to) { + var r = confirm("Do you want to connect the node to itself?"); + if (r === true) { + saveEdge(data, callback, "editEdge"); + } + } + else { saveEdge(data, callback, "editEdge"); } + }; + } else if(typeof(x.options.manipulation.editEdge) === typeof(true)){ + if(x.options.manipulation.editEdge){ + options.manipulation.editEdge = function(data, callback) { + if (data.from == data.to) { + var r = confirm("Do you want to connect the node to itself?"); + if (r === true) { + saveEdge(data, callback, "editEdge"); + } + } + else { + saveEdge(data, callback, "editEdge"); + } + }; + } else { + options.manipulation.editEdge = false; } - else { - saveEdge(data, callback, "editEdge"); - } - }; + } else { + options.manipulation.editEdge = x.options.manipulation.editEdge; + } } // create network @@ -2688,7 +3012,15 @@ HTMLWidgets.widget({ var popupState = false; var popupTimeout = null; var vispopup = document.createElement("div"); - var popupStyle = 'position: fixed;visibility:hidden;padding: 5px;white-space: nowrap;font-family: verdana;font-size:14px;font-color:#000000;background-color: #f5f4ed;-moz-border-radius: 3px;-webkit-border-radius: 3px;border-radius: 3px;border: 1px solid #808074;box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2)' + + // disable vis.js tooltip + var style = document.createElement('style'); + style.type = 'text/css'; + style.innerHTML = 'div.vis-tooltip {display : none}'; + document.getElementsByTagName('head')[0].appendChild(style); + + var popupStyle = 'position: fixed;visibility:hidden;padding: 5px;font-family: verdana;font-size:14px;font-color:#000000;background-color: #f5f4ed;-moz-border-radius: 3px;-webkit-border-radius: 3px;border-radius: 3px;border: 1px solid #808074;box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);max-width:400px;word-break: break-all' + if(x.tooltipStyle !== undefined){ popupStyle = x.tooltipStyle } @@ -3025,6 +3357,16 @@ HTMLWidgets.widget({ // all in degree nodes get their own color and their label back + main nodes connectedNodes = connectedNodes.concat(selectedNode); + + if (window.Shiny){ + Shiny.onInputChange(el.id + '_highlight_color_id', uniqueShiny(connectedNodes)); + } + if(el_id.highlightLabelOnly === true){ + if (window.Shiny){ + Shiny.onInputChange(el.id + '_highlight_label_id', allConnectedNodes.filter(function(x){ return !connectedNodes.includes(x)})); + } + } + array_cluster_id = []; for (i = 0; i < connectedNodes.length; i++) { resetOneNode(allNodes[connectedNodes[i]], instance.network.groups, options, instance.network); @@ -3034,7 +3376,7 @@ HTMLWidgets.widget({ } } } - + if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { @@ -3073,7 +3415,6 @@ HTMLWidgets.widget({ } } edges.update(edgesHardToRead); - } else if(algorithm === "hierarchical"){ var degree_from = degrees.from; @@ -3223,6 +3564,15 @@ HTMLWidgets.widget({ } } + if (window.Shiny){ + Shiny.onInputChange(el.id + '_highlight_color_id', uniqueShiny(allConnectedNodes)); + } + if(el_id.highlightLabelOnly === true){ + if (window.Shiny){ + Shiny.onInputChange(el.id + '_highlight_label_id', nodesWithLabel.filter(function(x) {return !allConnectedNodes.includes(x)})); + } + } + // set some edges as hard to read var edgesHardToRead = edges.get({ fields: ['id', 'color', 'hiddenColor', 'hiddenLabel', 'label'], @@ -3282,6 +3632,11 @@ HTMLWidgets.widget({ resetAllNodes(nodes, update, instance.network.groups, options, instance.network) el_id.highlightActive = false; is_clicked = false; + + if (window.Shiny){ + Shiny.onInputChange(el.id + '_highlight_label_id', null) + Shiny.onInputChange(el.id + '_highlight_color_id', null) + } } } // reset selectedBy list if actived @@ -3326,7 +3681,7 @@ HTMLWidgets.widget({ neighbourhoodHighlight(params.nodes, "click", el_id.highlightAlgorithm); }else if((el_id.idselection || el_id.byselection) && x.nodes){ onClickIDSelection(params) - } + } }; // Set event in relation with highlightNearest @@ -3355,8 +3710,9 @@ HTMLWidgets.widget({ //************************* instance.network.on("doubleClick", function(params){ if(el_id.collapse){ - collapsedNetwork(params.nodes, el_id.collapseFit, el_id.collapseResetHighlight, el_id.clusterOptions, - el_id.tree, instance.network, el.id) + collapsedNetwork(params.nodes, el_id.collapseFit, el_id.collapseResetHighlight, + el_id.clusterOptions, el_id.collapseLabelSuffix, + el_id.tree, instance.network, el.id) } }); @@ -3371,6 +3727,7 @@ HTMLWidgets.widget({ div_footer.id = "footer"+el.id; div_footer.setAttribute('style', 'font-family:Georgia, Times New Roman, Times, serif;font-size:12px;text-align:center;background-color: inherit;'); div_footer.style.display = 'none'; + document.getElementById("graph" + el.id).appendChild(div_footer); if(x.footer !== null){ div_footer.innerHTML = x.footer.text; @@ -3505,7 +3862,20 @@ HTMLWidgets.widget({ el_id.appendChild(clusterbutton); clusterbutton.onclick = function(){ - instance.network.setData(data); + // reset some parameters / data before + if (el_id.selectActive === true | el_id.highlightActive === true) { + //reset nodes + neighbourhoodHighlight([], "click", el_id.highlightAlgorithm); + if (el_id.selectActive === true){ + el_id.selectActive = false; + resetList('selectedBy',el.id, 'selectedBy'); + } + if (el_id.highlightActive === true){ + el_id.highlightActive = false; + resetList('nodeSelect', el.id, 'selected'); + } + } + //instance.network.setData(data); if(x.clusteringColor){ clusterByColor(); } @@ -3525,8 +3895,10 @@ HTMLWidgets.widget({ if(x.clusteringGroup || x.clusteringColor || x.clusteringOutliers || x.clusteringHubsize || x.clusteringConnection){ // if we click on a node, we want to open it up! instance.network.on("doubleClick", function (params){ + if (params.nodes.length === 1) { if (instance.network.isCluster(params.nodes[0]) === true) { + is_clicked = false; instance.network.openCluster(params.nodes[0], {releaseFunction : function(clusterPosition, containedNodesPositions) { return containedNodesPositions; }}); @@ -3555,8 +3927,12 @@ HTMLWidgets.widget({ function clusterByHubsize() { var clusterOptionsByData = { processProperties: function(clusterOptions, childNodes) { + var cluster_level = 9999999 for (var i = 0; i < childNodes.length; i++) { //totalMass += childNodes[i].mass; + if(childNodes[i].level){ + cluster_level = Math.min(cluster_level, childNodes[i].level) + } if(i === 0){ //clusterOptions.shape = childNodes[i].shape; clusterOptions.color = childNodes[i].color.background; @@ -3570,6 +3946,9 @@ HTMLWidgets.widget({ } } clusterOptions.label = "[" + childNodes.length + "]"; + if(cluster_level !== 9999999){ + clusterOptions.level = cluster_level + } return clusterOptions; }, clusterNodeProperties: {borderWidth:3, shape:'box', font:{size:30}} @@ -3594,28 +3973,37 @@ HTMLWidgets.widget({ var clusterOptionsByData; for (var i = 0; i < colors.length; i++) { var color = colors[i]; + var sh = x.clusteringColor.shape[i]; + var force = x.clusteringColor.force[i]; clusterOptionsByData = { joinCondition: function (childOptions) { return childOptions.color.background == color; // the color is fully defined in the node. }, processProperties: function (clusterOptions, childNodes, childEdges) { var totalMass = 0; + var cluster_level = 9999999; for (var i = 0; i < childNodes.length; i++) { totalMass += childNodes[i].mass; - if(x.clusteringColor.force === false){ + if(childNodes[i].level){ + cluster_level = Math.min(cluster_level, childNodes[i].level) + } + if(force === false){ if(i === 0){ clusterOptions.shape = childNodes[i].shape; }else{ if(childNodes[i].shape !== clusterOptions.shape){ - clusterOptions.shape = x.clusteringColor.shape; + clusterOptions.shape = sh; } } } else { - clusterOptions.shape = x.clusteringColor.shape; + clusterOptions.shape = sh; } } clusterOptions.value = totalMass; + if(cluster_level !== 9999999){ + clusterOptions.level = cluster_level + } return clusterOptions; }, clusterNodeProperties: {id: 'cluster:' + color, borderWidth: 3, color:color, label: x.clusteringColor.label + color} @@ -3637,33 +4025,46 @@ HTMLWidgets.widget({ var clusterOptionsByData; for (var i = 0; i < groups.length; i++) { var group = groups[i]; + var col = x.clusteringGroup.color[i]; + var sh = x.clusteringGroup.shape[i]; + var force = x.clusteringGroup.force[i]; + var sc_size = x.clusteringGroup.scale_size[i]; + clusterOptionsByData = { joinCondition: function (childOptions) { return childOptions.group == group; // }, processProperties: function (clusterOptions, childNodes, childEdges) { - //console.info(clusterOptions); var totalMass = 0; + var cluster_level = 9999999; for (var i = 0; i < childNodes.length; i++) { totalMass += childNodes[i].mass; - if(x.clusteringGroup.force === false){ + if(childNodes[i].level){ + cluster_level = Math.min(cluster_level, childNodes[i].level) + } + if(force === false){ if(i === 0){ clusterOptions.shape = childNodes[i].shape; clusterOptions.color = childNodes[i].color.background; }else{ if(childNodes[i].shape !== clusterOptions.shape){ - clusterOptions.shape = x.clusteringGroup.shape; + clusterOptions.shape = sh; } if(childNodes[i].color.background !== clusterOptions.color){ - clusterOptions.color = x.clusteringGroup.color; + clusterOptions.color = col; } } } else { - clusterOptions.shape = x.clusteringGroup.shape; - clusterOptions.color = x.clusteringGroup.color; + clusterOptions.shape = sh; + clusterOptions.color = col; } } - clusterOptions.value = totalMass; + if(sc_size){ + clusterOptions.value = totalMass; + } + if(cluster_level !== 9999999){ + clusterOptions.level = cluster_level + } return clusterOptions; }, clusterNodeProperties: {id: 'cluster:' + group, borderWidth: 3, label:x.clusteringGroup.label + group} @@ -3711,14 +4112,22 @@ HTMLWidgets.widget({ processProperties: function (clusterOptions, childNodes) { clusterIndex = clusterIndex + 1; var childrenCount = 0; + var cluster_level = 9999999; for (var i = 0; i < childNodes.length; i++) { childrenCount += childNodes[i].childrenCount || 1; + if(childNodes[i].level){ + cluster_level = Math.min(cluster_level, childNodes[i].level) + } } clusterOptions.childrenCount = childrenCount; clusterOptions.label = "# " + childrenCount + ""; clusterOptions.font = {size: childrenCount*5+30} clusterOptions.id = 'cluster:' + clusterIndex; clusters.push({id:'cluster:' + clusterIndex, scale:scale}); + + if(cluster_level !== 9999999){ + clusterOptions.level = cluster_level + } return clusterOptions; }, clusterNodeProperties: {borderWidth: 3, shape: 'database', font: {size: 30}} @@ -3772,10 +4181,12 @@ HTMLWidgets.widget({ instance.network.redraw(); if(instance.legend) instance.legend.redraw(); - }, 200); - } + }, 250); + }; + if(x.iconsRedraw !== undefined){ if(x.iconsRedraw){ + iconsRedraw(); instance.network.once("stabilized", function(){iconsRedraw();}) } } diff --git a/docs/authors.html b/docs/authors.html index d88ef323..46aa3cb6 100644 --- a/docs/authors.html +++ b/docs/authors.html @@ -1,6 +1,6 @@ - + @@ -9,27 +9,34 @@ Authors • pkgnet - + - + - + - + - + + + + - + + + + - + + - - @@ -47,14 +52,15 @@