thomasp85 / ggfx

Filters and Shaders for 'ggplot2'
https://ggfx.data-imaginist.com
Other
167 stars 4 forks source link

function to calculate pixel coordinate from axis coordinate #23

Closed steveharoz closed 2 years ago

steveharoz commented 2 years ago

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"
  )
thomasp85 commented 2 years ago

I assume it is because you want something different, but just to let you know, the "." shape will draw a pixel-sized dot, so you could get by doing something like

ggplot(aes(x=x, y=y)) + 
  annotate(
    "point",
    x = 0, y = 0,
    shape = ".",
    color = "red"
  )
steveharoz commented 2 years ago

Thanks, but that's just a simple test case 😁.

What I actually want is to do some pixel shading at a few data-dependent locations, but there doesn't seem to be a way to call the filter per point rather than per layer. Making geom_point(size=20) and constraining the viewport to the surface of each point would be ideal.

If there isn't a simple way to transform from axis coordinates to pixel location, I wonder if passing in a couple dots would allow me to sort of reverse engineer the transformation based on which pixels are lit up.

tibble(x=-1:5, y=-1:5) %>% 
  ggplot(aes(x=x, y=y)) + 
  with_custom(
    geom_point(x = 0:1, y = 0:1, shape = "."),
    filter = my_filter,
    filter_data = tibble(x=-1:5, y=-1:5)
  )
thomasp85 commented 2 years ago

yeah, I feared that was the case :-) ... ggfx is quite oblivious to what goes on inside ggplot2 so scales are hidden from it - can you describe a bit more clearly what you are trying to achieve and I'll see if I can come up with a path of least resistance

steveharoz commented 2 years ago

I'd like to render a mathematically-defined 2D function (specifically, a Gabor function) at a few different locations on the plot. And I want to animate them with gganimate. Each will have different parameters which change over time, so just stamping on premade images with magick won't work.

Maybe using ggfx isn't the way to go, but it's the best approach I could think of for per-pixel rendering. I could use geom_raster, but (1) it wouldn't be aware of pixels, so it'd look aliased, and (2) it'd need a whole layer per item.

steveharoz commented 2 years ago

Since the request seems complicated, geom_raster may actually be the way to go. I thought ggfx had some simple coord->pixel transformation. But if not, I think I figured it out in geom_raster, although it is SLOW. Thanks for letting me bounce ideas off of you Thomas! image