Giter VIP home page Giter VIP logo

ggfx's Introduction

ggfx

Lifecycle: experimental Codecov test coverage R-CMD-check

ggfx is a (currently experimantal) package that allows the use of various filters and shaders on ggplot2 layers.

Installation

You can install ggfx from CRAN in the usual manner (install.packages('ggfx')) or you can grab the development version directly from github using the devtools package:

# install.packages('devtools')
devtools::install_github('thomasp85/ggfx')

Example

The basic API of ggfx is to provide a range of with_*() modifier functions instead of special versions of common geoms. This means that ggfx will work with any geom from ggplot2 and the extension packages (I think…). An example showing some of the different functionalities are given below. Note that the output is produced with regular geoms.

library(ggplot2)
library(ggfx)
ggplot() + 
  as_reference(
    geom_polygon(aes(c(0, 1, 1), c(0, 0, 1)), colour = NA, fill = 'magenta'), 
    id = "displace_map"
  ) + 
  with_displacement(
    geom_text(aes(0.5, 0.5, label = 'ggfx-ggfx'), size = 25, fontface = 'bold'), 
    x_map = ch_red("displace_map"), 
    y_map = ch_blue("displace_map"),
    x_scale = unit(0.025, 'npc'),
    id = "text"
  ) +
  with_blend(
    geom_density_2d_filled(aes(rnorm(1e4, 0.5, 0.2), rnorm(1e4, 0.5, 0.2)), 
                           show.legend = FALSE),
    bg_layer = "text",
    blend_type = "in",
    id = "blended"
  ) + 
  with_shadow("blended", sigma = 3) + 
  coord_cartesian(xlim = c(0, 1), ylim = c(0, 1), clip = 'off') + 
  labs(x = NULL, y = NULL)

Code of Conduct

Please note that the ggfx project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.

ggfx's People

Contributors

jeroen avatar thomasp85 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ggfx's Issues

with_outer_glow() - Negative values not shown

Labels with negative values passed to with_outer_glow, seem to lose their "-" sign.

See following example...

example contour plots

library(ggplot2)
library(geomtextpath)
library(ggfx)
df <- expand.grid(x = seq(nrow(volcano)), y = seq(ncol(volcano)))
df$z <- as.vector(volcano)-150 #make some values negative

this works - shows negative numbers

ggplot(df, aes(x, y, z = z)) +
geom_contour_filled(bins = 6, alpha = 0.6) +
geom_textcontour(bins = 6, size = 3, linetype = NA)

this doesn't work - negative numbers not shown

ggplot(df, aes(x, y, z = z)) +
geom_contour_filled(bins = 6, alpha = 0.6) +
with_outer_glow(
geom_textcontour(aes(z = z), linetype = NA, size = 3),
colour = 'white',
expand = 5,
sigma = 1
)

Release ggfx 1.0.1

Prepare for release:

  • git pull
  • Check current CRAN check results
  • Polish NEWS
  • devtools::build_readme()
  • urlchecker::url_check()
  • devtools::check(remote = TRUE, manual = TRUE)
  • devtools::check_win_devel()
  • rhub::check_for_cran()
  • revdepcheck::cloud_check()
  • Update cran-comments.md
  • git push

Submit to CRAN:

  • usethis::use_version('patch')
  • devtools::submit_cran()
  • Approve email

Wait for CRAN...

  • Accepted πŸŽ‰
  • git push
  • usethis::use_github_release()
  • usethis::use_dev_version()
  • git push

reduce dependence on magick API

We are using magick for now but it is slow. The ggfx API should not expose magick specific settings so it can be easier to switch to a more performant backend (shaders) when possible

is it possible to manually adjust the resolution of with_raster()?

Hi πŸ‘‹,

I want to apologize if this is the wrong place for this, since this likely is more of a feature-wish than an issue 😬.

Basically, I love the idea of with_raster(), but currently I am only able to control the resolution (dpi on the final figure) of the rasterized ggplot layer indirectly, by up-scaling the exported figure. Yet, when trying to keep plot configurations consistent over many plots (eg for a scientific publication), this forces one to also correct a zillion of other settings (font size, line widths, symbol sizes etc).

Hence, my question: is it possible to somehow adjust the resolution of with_raster() (now or potentially in the future)?
(Also - apologies if this is a case where I am just to silly to RTFM correctly 😨)

Additional raster helpers

  • get_viewport_area() / set_viewport_area()
  • get_viewport_cols_rows()
  • get_raster_area() / set_raster_area()

drawing confidence intervals properly

The idea to use blurs for confidence intervals is great. But I fear result shown here : https://ggfx.data-imaginist.com/articles/geoms.html for confidence intervals is not useful (sorry, I don't want to be harsh).

To explain:
Blurring should result in a figure in which regions with the same confidence interval level have the same color density/opacity/brightness.

Some thing like this, just smoother:
p = ggplot(mpg, aes(displ, hwy))
for (l in seq(5,95,5)/100)
p = p + geom_smooth(level = l, alpha = .1, fill = "blue", method = "loess", size = 0)
p

cheers - Guido

function to calculate pixel coordinate from axis coordinate

Feature Request

Would it be possible to specify a location in axis coordinates and get the pixel index?

This is an example of trying to set the pixel corresponding to x=0, y=0 to red. Note that calculate_pixel_index_of_coordinate() is a placeholder for the function I'm looking for.

zero_zero_dot = function(the_raster, color) {
  viewport_location() %>% cat()
  # find the pixel that corresponds to (x=0, y=0)
  zero_pixel_index = calculate_pixel_index_of_coordinate(the_raster, x=0, y=0)
  # set that pixel's color
  the_raster[zero_pixel_index] <- farver::encode_native(color)
  
  the_raster
}


tibble(x=-1:5, y=-1:5) %>% 
  ggplot(aes(x=x, y=y)) + 
  with_custom(
    geom_point(),
    filter = zero_zero_dot,
    color = "red"
  )

Pixelated output from with_mask()

Hi,

Love the package. But I've been having some issue recently when using the with_mask function. The output is quite pixelated, to the point of being unusable for a few use-cases (generative art).

Below is a reproducible example that just plots some random points, where if using a mask, the result is pixelated regardless of how the image is exported. I am using the latest version of ggfx from the github repo and ggplot2 β€˜3.4.0’.

Thanks in advance for any help

library(tidyverse)
library(ggfx)

test_data <- tibble(
  x = rnorm(2000, 0, 10),
  y = rnorm(2000, 0, 10),
)

circle <- tibble(
  x = cos(seq(0, 2*pi, length.out = 360)),
  y = sin(seq(0, 2*pi, length.out = 360))
) |> 
  mutate(across(everything(), ~ .x * 25))

# the output here is very pixelated
ggplot() +
  lims(x = c(-30, 30), y = c(-30, 30)) +
  coord_equal() +
  theme_void() +
  as_reference(
    geom_polygon(aes(x = x, y = y), circle),
    id = 'circle'
  ) +
  with_mask(
    geom_point(data = test_data, aes(x,y)),
    mask = ch_alpha('circle'),
    invert = FALSE,
    ignore_background = FALSE
  )
  
  # however if I just plot without the mask as a usual ggplot, it is fine:
  ggplot(test_data, aes(x,y)) +
  geom_point() +
  lims(x = c(-30, 30), y = c(-30, 30)) +
  coord_equal() +
  theme_void() 

'color' doesn't work in with_outer_glow()

I have only tried this with with_outer_glow():
colour works, but not color πŸ™‚

ggplot() +
  with_outer_glow(
    geom_point(aes(x = 0, y = 0), size = 10),
    color = "red",
    expand = 10
  )

Rplot

Release ggfx 1.0.0

First release:

Prepare for release:

  • devtools::build_readme()
  • urlchecker::url_check()
  • devtools::check(remote = TRUE, manual = TRUE)
  • devtools::check_win_devel()
  • rhub::check_for_cran()
  • Review pkgdown reference index for, e.g., missing topics
  • Draft blog post

Submit to CRAN:

  • usethis::use_version('major')
  • devtools::submit_cran()
  • Approve email

Wait for CRAN...

  • Accepted πŸŽ‰
  • usethis::use_github_release()
  • usethis::use_news_md()
  • usethis::use_dev_version()
  • Update install instructions in README
  • Finish blog post
  • Tweet
  • Add link to blog post in pkgdown news menu

Unexpected behavior with_mask and with_shadow output

Hi, I found what I think is a bug when you combine with_mask and with_shadow. I think the shadow is being put on top of the used path.

# Suspected bug
ggplot(df) +
  geom_path(aes(x,y),
            color="#4bc4ff",linewidth=20,lineend="round" ) +
  with_shadow(
    geom_path(data=df[-3,],aes(x,y),
            color="blue",linewidth=20,lineend="round" ),
    stack=TRUE,x_offset = 0,y_offset = 0,sigma = 20,id="bar") +
  with_mask(
    geom_path(data=df,
              aes(x,y),
              linewidth=20,lineend='round'),
    mask=ch_alpha('bar')
  )

# Desired output
ggplot(df) +
  geom_path(aes(x,y),
            color="#4bc4ff",linewidth=20,lineend="round" ) +
  with_shadow(
    geom_path(data=df[-3,],aes(x,y),
              color="blue",linewidth=20,lineend="round" ),
    stack=FALSE,x_offset = 0,y_offset = 0,sigma = 20,id="bar") +
  with_mask(
    geom_path(data=df,
              aes(x,y),
              linewidth=20,lineend='round'),
    mask=ch_alpha('bar')
  ) +
  geom_path(data=df[-3,],aes(x,y),
            color="blue",linewidth=20,lineend="round" )


Expected output:
image

Actual output:
image

Error with custom filter and theme_void()

Adding theme_void() to a plot with a custom filter using Magick results in an error. When testing with other theme functions such as theme_minimal() or theme_classic() it works fine. Small reprex based on the example in the documentation:

library(ggplot2)
library(ggfx)

# Example from documentation
implode <- function(x, factor = 0.5) {
  vp <- magick::image_read(get_viewport_area(x))
  vp <- magick::image_implode(vp, factor = factor)
  set_viewport_area(x, as.raster(vp, native = TRUE))
}

ggplot(mtcars, aes(x = factor(gear), y = disp)) +
  with_custom(
    geom_boxplot(aes(fill = as.factor(gear))),
    filter = implode
  ) 

# Adding theme_void() returns an error
# Other theme_*() functions don't seem to have this issue
ggplot(mtcars, aes(x = factor(gear), y = disp)) +
  with_custom(
    geom_boxplot(aes(fill = as.factor(gear))),
    filter = implode
  ) +
  theme_void()
#> Error in .subset(raster, index): only 0's may be mixed with negative subscripts

Created on 2023-08-25 with reprex v2.0.2

geom_line() - Error in validDetails.polyline(x): invalid 'arrow' argument

Thanks for working on this - it's a great idea. I suspect i'm doing something wrong and I know this is in early stages so wouldn't expect everything to work but wanted to flag - just incase it might be useful. I have tried a few different geoms with the example plot in the documentation but it didn't seem to like geom_line (others worked ok).

library(ggplot2)
library(ggfx)

ggplot(mtcars, aes(mpg, disp)) + 
    with_shadow(geom_line(colour = 'red', size = 3), sigma = 3) +
    geom_line()
#> Error in validDetails.polyline(x): invalid 'arrow' argument

It may have something to do with this in {grid} (though it may not):

######################################
# POLYLINES primitive
######################################
# Very similar to LINES primitive, but allows
# multiple polylines via 'id' and 'id.lengths' args
# as per POLYGON primitive
validDetails.polyline <- function(x) {
  if (!is.unit(x$x) ||
      !is.unit(x$y))
      stop("'x' and 'y' must be units")
  if (!is.null(x$id) && !is.null(x$id.lengths))
      stop("it is invalid to specify both 'id' and 'id.lengths'")
  if (length(x$x) != length(x$y))
      stop("'x' and 'y' must be same length")
  if (!is.null(x$id) && (length(x$id) != length(x$x)))
      stop("'x' and 'y' and 'id' must all be same length")
  if (!is.null(x$id))
      x$id <- as.integer(x$id)
  if (!is.null(x$id.lengths) && (sum(x$id.lengths) != length(x$x)))
      stop("'x' and 'y' and 'id.lengths' must specify same overall length")
  if (!is.null(x$id.lengths))
      x$id.lengths <- as.integer(x$id.lengths)
  if (!(is.null(x$arrow) || inherits(x$arrow, "arrow")))
      stop("invalid 'arrow' argument")
  x
}

Vector output seems not possible

When we use ggfx::with_outer_glow (and presumably other ggfx functions) the resulting output is converted to bitmap. Is this intended behaviour?

require(tidyverse)
require(sf)

j0 = jsonlite::fromJSON('https://petition.parliament.uk/petitions/554276.json')
d0 = j0$data$attributes$signatures_by_constituency |> as_tibble()
g = sf::read_sf('https://petitionmap.unboxedconsulting.com/json/uk/uk/topo_wpc.json')
d = g |> left_join(d0, by = c(id = 'ons_code')) |> st_set_crs(4326) |> st_transform("EPSG:27700")

# vector output
p1 = ggplot() + 
  geom_sf(aes(fill = signature_count), data = d, col = 'white', linewidth=0.03) +
  coord_sf(ylim = c(5e4, 9.6e5)) +
  scale_fill_viridis_c(direction = -1) +
  theme_void() +
  # theme(plot.background = element_rect(fill = 'grey90', colour = NA)) +
  labs(fill = 'Signatures')

ggsave(p1, filename = 'map1.pdf', width = 30, height = 45); browseURL('map1.pdf')

# When we use with_outer_glow the resulting map bitmap
p2 = ggplot() + 
  ggfx::with_outer_glow(
    geom_sf(aes(fill = signature_count), data = d, col = 'white', linewidth=0.03),
    colour = 'lightblue1',
    sigma = 10,
    expand = 2
  ) +
  coord_sf(ylim = c(5e4, 9.6e5)) +
  scale_fill_viridis_c(direction = -1) +
  theme_void() +
  labs(fill = 'Signatures')

ggsave(p2, filename = 'map2.pdf', width = 30, height = 45); browseURL('map2.pdf')

Output of map2 looks like this up close:

image

Functions tripping up on geom_sf()?

Very possible I've missed some key understanding, but at first pass it appears that some functions, specifically as_reference() and with_shadow() do not work with sf objects/geom_sf(). Looks to be some incompatibility with sf's geometry list columns? I keep getting Error in UseMethod("with_shadow") : no applicable method for 'with_shadow' applied to an object of class "list"

Reprex:

library(tidyverse)
library(sf)
library(ggfx)

nc <- st_read(system.file("shape/nc.shp", package="sf"))

ggplot(nc) +
  as_reference(
    geom_sf(data = nc,
            aes(fill = BIR79)),
    id = "nc"
)

ggplot(nc) +
  with_shadow(
    geom_sf(aes(fill = BIR79)),
    sigma = 3
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.