Skip to content

Commit

Permalink
Updated gridGeometry dependency to 0.4.1; added rotate_degrees for ve…
Browse files Browse the repository at this point in the history
…nndir(); reduced buffer_JamPolygon() steps for speed.
  • Loading branch information
jmw86069 committed Sep 3, 2024
1 parent d23045d commit b9bc0a1
Show file tree
Hide file tree
Showing 177 changed files with 850 additions and 406 deletions.
7 changes: 4 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: venndir
Title: Directional Venn diagrams
Version: 0.0.39.900
Version: 0.0.39.950
Authors@R: c(
person(given="James M.",
family="Ward",
Expand All @@ -20,7 +20,7 @@ Imports: jamba(>= 0.0.101.900),
gridBase,
data.table,
gridExtra,
gridGeometry,
gridGeometry(>= 0.4.1),
methods
Suggests:
eulerr,
Expand All @@ -34,7 +34,8 @@ License: MIT
Encoding: UTF-8
LazyData: true
Remotes: github::jmw86069/jamba,
github::jmw86069/colorjam
github::jmw86069/colorjam,
github::pmur002/gridgeometry
URL: http://github.com/jmw86069/venndir
BugReports: http://github.com/jmw86069/venndir/issues
Roxygen: list(markdown = TRUE)
Expand Down
19 changes: 19 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# venndir 0.0.39.950

* Small change to use `gridGeometry` 0.4.1 from Github until released to CRAN,
this version fixes rare error caused by proportional diagram and innerborder,
when the delta from two circles creates a small line with zero area.
Will update again once it is available on CRAN.
Thanks pmur002 for the rapid fix!

* Updated tests from 0.0.39.900 which skipped the innerborder to
circumvent the bug in the tests that uncovered the error.

* `buffer_JamPolygon()`

* default argument `steps=20`, formerly `steps=200` which was (and is)
the predominant rate-limiting step.

* `nudge_JamPolygon()` now recognizes `rotate_degrees` fixing the bug that
previously did not allow rotating the Venn diagram polygons.

# venndir 0.0.39.900

## changes to existing functions
Expand Down
51 changes: 42 additions & 9 deletions R/JamPolygon.R
Original file line number Diff line number Diff line change
Expand Up @@ -1898,8 +1898,10 @@ point_in_JamPolygon <- function
#' @family JamPolygon
#'
#' @returns `logical` vector with one result per point `x`, where
#' `TRUE` indicates the point overlaps at least one polygon, and
#' `FALSE` indicates the point does not overlap any polygon.
#' * `TRUE` indicates the point overlaps at least one polygon,
#' * `FALSE` indicates the point does not overlap any polygon.
#' * Note that a point contained in a polygon "hole" is expected
#' to return `FALSE` when `apply_holes=TRUE` (default).
#'
#' @param x `list` with `"x"`,`"y"` with `numeric` values, representing
#' one or more points.
Expand Down Expand Up @@ -1929,11 +1931,18 @@ has_point_in_JamPolygon <- function

#' Split JamPolygon multipart polygons
#'
#' Split JamPolygon multipart polygons into separate polygons, one
#' polygon per row in `jp@polygons`.
#'
#' @family JamPolygon
#'
#'
#' @returns `JamPolygon` with one row per distinct polygon part in the
#' input `jp` object.
#'
#' @param jp `JamPolygon`
#' @param suffix `character` passed to `jamba::makeNames()` when creating
#' new unique `names()` for the resulting polygons.
#' new unique `names()` for the resulting polygons. The default `"_sub"`
#' will create sub-parts with `"_sub1"`, `"_sub2"`, `"_sub3"`, and so on.
#' @param ... additional arguments are ignored.
#'
#' @export
Expand Down Expand Up @@ -1967,6 +1976,7 @@ split_JamPolygon <- function
new_jp <- jp;
new_jp@polygons <- jp@polygons[rowseq, , drop=FALSE];
names(new_jp) <- jamba::makeNames(names(new_jp), ...);
# rownames(new_jp@polygons) <- names(new_jp);
new_jp@polygons$x <- I(new_x);
new_jp@polygons$y <- I(new_y);

Expand All @@ -1978,6 +1988,19 @@ split_JamPolygon <- function

#' Update attributes for a JamPolygon object
#'
#' Update attributes for a JamPolygon object, including default label
#' position, and polygon orientations.
#'
#' The default label position is defined with `"label_x","label_y"`
#' if these columns do not already exist in `jp@polygons`.
#' The coordinates are defined by `labelr_JamPolygon()` with
#' argument `add_to_jp=TRUE`.
#'
#' If the column `"orientation"` does not exist in `jp@polygons`
#' it is added by calling `add_orientation_JamPolygon()`. It
#' subsequently adds columns `"holes"`, `"polygon_clockwise"`, and
#' `"polygon_parent"` when each is not already present.
#'
#' @family JamPolygon
#'
#' @params jp `JamPolygon`
Expand Down Expand Up @@ -2157,10 +2180,20 @@ sample_JamPolygon <- function
} else {
use_jp <- jp;
}
## Todo: Fix error with use_jp has zero x,y coordinates
# - bbox_JamPolygon() creates c(-Inf,Inf) bbox values
# - jp has empty x,y coordinates
# - buffer_JamPolygon() may create use_jp with empty x,y coordinates
# jamba::printDebug("jp:");print(jp);# debug
# jamba::printDebug("use_jp:");print(use_jp);# debug
if (length(jamba::rmNA(unlist(jp@polygons$x))) == 0) {
return(list(x=numeric(0),
y=numeric(0)));
}

# bounding box
xyrange <- bbox_JamPolygon(use_jp);

# custom function to wrap some re-usable logic
array_points <- function
(xyrange,
Expand Down Expand Up @@ -2228,9 +2261,7 @@ sample_JamPolygon <- function

# range of values for n to attempt
n_seq <- unique(round(seq(from=n * 1, to=n * 50, by=ceiling(n / 50))));
# jamba::printDebug("sample_JamPolygon(): ",
# "n_seq: ", n_seq);


# define n points inside the polygon
n_ratio <- head(n_ratio, 1);
if (length(n_ratio) == 0 || any(n_ratio) < 1) {
Expand All @@ -2240,6 +2271,8 @@ sample_JamPolygon <- function
n_ratio <- 1;
}
for (try_n in n_seq) {
# jamba::printDebug("sample_JamPolygon(): ", "try_n:", try_n);# debug
# jamba::printDebug("use_jp:");print(use_jp);# debug
A <- array_points(xyrange,
n=try_n,
pattern=pattern,
Expand Down Expand Up @@ -2360,7 +2393,7 @@ sample_JamPolygon <- function
buffer_JamPolygon <- function
(jp,
buffer=-0.5,
steps=200,
steps=20,
relative=TRUE,
verbose=FALSE,
...)
Expand Down
135 changes: 101 additions & 34 deletions R/venndir-label-fill-jp.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
#' Arrange text labels inside a polygon
#'
#' Arrange text labels inside a polygon
#' Arrange one or more text labels to fit inside a polygon.
#'
#' This function is intended to define points inside a polygon area
#' which are evenly spaced, used to place text labels also inside
#' the polygon. There are limited options to define a buffer region
#' so that labels do not overlap the polygon boundary.
#' so that text labels can be roughly evenly spaced, with relatively
#' good default positioning to minimize overlapping labels.
#' This function does not prevent overlapping labels, nor does it
#' fully prevent labels overlapping the polygon border.
#'
#' There are options to help minimize overlapping labels, such as `xyratio`
#' which defines the default width-to-height ratio of resulting points.
#' For wider text labels, a higher value for `xyratio` may be helpful.
#' To minimize adjacent (side-by-side) label overlaps, it can be helpful
#' to use `degrees` to rotate labels slightly, for example `degrees=5`
#' may be enough to prevent wide labels from overlapping the next label
#' beside it.
#'
#' ## Strategy
#'
Expand All @@ -16,24 +25,88 @@
#' * If there are fewer than `n` remaining points, repeat the process
#' using a higher target value for `n`.
#'
#' Challenges:
#'
#' * `polyclip::pointinpolygon()` does not appear to handle polygons with
#' holes. If not, then we have to use logic like: "overlaps any solid polygon,
#' does not overlap any polygon hole".
#'
#' Options:
#' ## Todo
#'
#' * Consider applying a buffer with fixed width inside the original
#' polygon, so that points have at least this minimum width to the
#' polygon border.
#' * Bonus points for applying the buffer more to the width than height,
#' since text labels are typically wider than they are tall.
#' * Modify options that plot the result so they work together with
#' `plot.JamPolygon()`.
#'
#' @family JamPolygon
#'
#' @returns `list` when there are valid coordinates, `NULL` otherwise.
#' The `list` contains these elements:
#' * `"items_df"`: a `data.frame` with columns
#' `x,y,text,rot,color,fontsize,border`
#' * `"g_labels"`: a grid `grob` graphical object only when
#' `plot_style="base"`, otherwise `NULL`
#' * `"scale_width"`: a `numeric` value indicating the `buffer` used
#' * `"jp_buffer"`: a `JamPolygon` object after adjusting with `buffer`
#'
#' @param jp `JamPolygon` where only the first row is processed.
#' @param labels `character` vector of labels
#' @param buffer `numeric` value (default `-0.15`) buffer to resize the
#' polygon, where negative values shrink the polygon size relative
#' to the size of the polygon. For example `-0.9` will reduce the polygon
#' 90% of the way toward a completely empty polygon, where that range
#' is defined by the width inside the polygon border.
#' @param relative `logical` passed to `buffer_JamPolygon()` (default `TRUE`)
#' to define `buffer` with relative coordinates.
#' @param color `character` string to define the color of resulting labels.
#' @param border `character` string used to define an optional item border,
#' which is only useful when `gridtext` is used to visualize labels.
#' @param ref_jp `JamPolygon` (optional) used only when `apply_n_scale=TRUE`,
#' used to define the overall plot range before determining whether
#' the internal area of `jp` should be reduced before arraying item
#' label coordinates.
#' The general idea is that polygons which are a smaller percentage
#' of the total area should not be reduced as much by `apply_n_scale`
#' because they have limited area, but larger polygons should receive
#' closer to the full `apply_n_scale` adjustment.
#' @param xyratio `numeric` value indicating the relative ratio of x (width)
#' to y (height) when arraying coordinates inside the polygons.
#' Values larger than `1` will place points wider from each other than
#' they are tall, which can help with longer text labels.
#' @param fontsize `numeric` font size in points, default `10`.
#' @param cex `numeric` multiplied by `fontsize` as an alternative convenient
#' way to adjust text label sizes.
#' @param degrees `numeric` value used to rotate labels, default `0`,
#' in degrees between 0 and 359.
#' @param `dither_cex,dither_color,dither_degrees` values used to provide
#' some variability to the repeated pattern of text labels.
#' * `dither_cex` provides a range to adjust `cex` and `fontsize` slightly
#' for each label, making some slightly larger or smaller to help
#' distinguish adjacent labels from one another.
#' * `dither_color` provides a range for adjusting the font color, which
#' is applied with `darkFactor` in `jamba::makeColorDarker()`.
#' * `dither_degrees` provides a range for adjusting font `degrees`,
#' the default `0` means the values are not adjusted. The `text()` function
#' does not permit multiple vectorized rotations, however `gridtext`
#' does permit multiple angles. Best to use `dither_degrees` only
#' when displaying labels with `gridtext`.
#' @param apply_n_scale `logical` indicating whether to adjust the buffer
#' based upon the number of items, where more items uses less buffer,
#' and fewer items imposes a larger buffer.
#' The intent is for a single label or small number of labels to
#' appear near the center.
#' @param label_method `character` string (default "hexagonal") to define
#' the label layout. Currently only `"hexagonal"` is implemented.
#' After testing some approaches in `sf::st_sample()` and
#' `spatstat.random::rThomas()`, the other options were interesting
#' but ultimately not more effective specifically for character labels.
#' Both packages have heavy R dependencies and were avoided.
#' @param draw_labels `logical` (default `TRUE`) indicating whether to
#' draw labels, however it is only used when `plot_style="base"`.
#' @param seed `numeric` value (default `1`) used to define the random seed
#' with `set.seed(seed)` for reproducible output.
#' When `seed` is `NULL` there is no call to `set.seed()`.
#' @param plot_style `character` string (deprecated) to define the
#' plot output, used only when `draw_labels=TRUE`.
#' Currently, labels are only rendered for `plot_style="base"`.
#' * `"base"`: Use R base plotting, using `gridBase` with `gridtext`.
#' * `"gg"`: Use `ggplot2` style plotting.
#' * `"none"`: No plot output.
#' @param verbose `logical` indicating whether to print verbose output.
#' @param ... additional arguments are passed to internal functions:
#' `buffer_JamPolygon()`, and `sample_JamPolygon()`.
#'
#' @examples
#' df3 <- data.frame(name=c("polygon1", "polygon2"),
Expand All @@ -59,15 +132,10 @@
#' plot(jp3);
#'
#' lfj <- label_fill_JamPolygon(jp3[1,], labels=1:20)
#' lfj12 <- label_fill_JamPolygon(jp3, labels=1:20)
#' plot(lfj$items_df[, c("x", "y")], cex=0)
#' text(lfj$items_df[, c("x", "y")], labels=lfj$items_df$text)
#'
#' #test_x <- jp3[1,]@polygons$x[[1]];
#' #test_y <- jp3[1,]@polygons$y[[1]];
#' #P <- list(x=c(3.5, 4.5), y=c(3.5, 4.5))
#' #A <- lapply(seq_along(test_x), function(i){
#' # list(x=test_x[[i]], y=test_y[[i]])})
#'
#' @export
label_fill_JamPolygon <- function
(jp,
Expand All @@ -84,16 +152,8 @@ label_fill_JamPolygon <- function
dither_cex=0.04,
dither_color=0.07,
dither_degrees=0,
scale_width=-0.15,
apply_n_scale=TRUE,
buffer_w=0,
buffer_h=0,
label_method=c("hexagonal"),
layout_degrees=-20,
draw_buffer=FALSE,
buffer_fill="#FFFFFF77",
buffer_border="red",
draw_points=FALSE,
draw_labels=TRUE,
seed=1,
plot_style=c("base", "gg", "none"),
Expand All @@ -113,7 +173,11 @@ label_fill_JamPolygon <- function
if (length(jp) == 0) {
return(NULL)
}

## Check for empty coordinates
if (length(jamba::rmNA(unlist(jp@polygons$x))) == 0) {
return(NULL)
}

## expand vectors to the number of labels
color <- rep(color, length.out=n);
border <- rep(border, length.out=n);
Expand Down Expand Up @@ -167,8 +231,11 @@ label_fill_JamPolygon <- function
relative=relative,
...)
}
#

## Check for empty coordinates
if (length(jamba::rmNA(unlist(jp@polygons$x))) == 0) {
return(NULL)
}

###################################################################
# item coordinates
# note that it sometimes requires iterations with increasing
Expand Down Expand Up @@ -216,7 +283,7 @@ label_fill_JamPolygon <- function
col=border
)
);
if (draw_labels) {
if (TRUE %in% draw_labels) {
## Draw labels
# to draw using grid we have to use a custom viewport
if (length(dev.list()) > 0) {
Expand Down
2 changes: 1 addition & 1 deletion R/venndir-meme.R
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
#' # by default any hidden overlaps do not trigger a warning to be displayed
#' # Note: using shape="circle" triggers an error in polygon_label_fill()
#' # that needs to be debugged
#' # venn_meme(wtah, proportional=TRUE)
#' # venn_meme(wtah, proportional=TRUE, shape="circle")
#'
#' # for proportional diagrams it may be helpful to use shape="ellipse"
#' venn_meme(wtah, proportional=TRUE, shape="ellipse")
Expand Down
Loading

0 comments on commit b9bc0a1

Please sign in to comment.