Skip to content

geom_tile borders missing notch at top left corners #3037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
DanielReedOcean opened this issue Dec 14, 2018 · 22 comments · Fixed by #3050
Closed

geom_tile borders missing notch at top left corners #3037

DanielReedOcean opened this issue Dec 14, 2018 · 22 comments · Fixed by #3050

Comments

@DanielReedOcean
Copy link

This is an issue that has been discussed over at Stackoverflow. The original problem can be found here. A minimal reprex is included below.

I have the following data frame:

# Dummy data frame
df <- expand.grid(x = 1:3, y = 1:3)

I would like to plot it as a geom_tile using ggplot2 like so:

# Tile plot
ggplot(df) + 
  geom_tile(aes(x = x, y = y), 
            fill = NA, colour = "red", size = 3, width = 0.7, height = 0.7)

which gives,

rplot

Notice that in the top left corner of each tile the border has a notch missing and that the corner doesn't dovetail nicely like the other corners. The outcome I expected was a square around each tile, perhaps something like this:

rplot01

A solution offered here by Z. Lin in that Stackoverflow thread suggests that linejoin and lineend for geom_tile are switched to mitre and square, respectively. Or, that they are at least offered as parameters in the geom so that the user can choose for themselves. Hopefully, this demonstrates my issue adequately, but please let me know if I can clarify any aspect.

@yutannihilation
Copy link
Member

Or, that they are at least offered as parameters in the geom so that the user can choose for themselves.

Thanks, agreed.

@ptoche
Copy link

ptoche commented Dec 15, 2018

Just a comment in passing. Ignore if off topic.

from https://github.com/tidyverse/ggplot2/blob/master/R/geom-tile.r

the first few lines:

#' geom_rect and geom_tile do the same thing, but are
#' parameterised differently: geom_rect uses the locations of the four
#' corners (xmin, xmax, ymin and ymax), while
#' geom_tile uses the center of the tile and its size (x,
#' y, width, height).

which is precisely the problem with geom_title.

Can you achieve your goal with geom_rect instead?

@yutannihilation
Copy link
Member

I don't think it matters.

library(ggplot2)

df <- expand.grid(x = 1:3, y = 1:3)
width <- 0.7
height <- 0.7

df$xmin <- df$x - width / 2
df$xmax <- df$x + width / 2
df$ymin <- df$y - height / 2
df$ymax <- df$y + height / 2

ggplot(df) + 
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), 
            fill = NA, colour = "red", size = 3)

Created on 2018-12-16 by the reprex package (v0.2.1)

@thomasp85
Copy link
Member

The problem is that the rectangles gets converted to polygons in closed form (first point gets repeated in the end), whereas polygonGrob expect an open representation... should be fairly easy to fix here:

ggplot2/R/geom-rect.r

Lines 75 to 80 in 9eae13b

rect_to_poly <- function(xmin, xmax, ymin, ymax) {
new_data_frame(list(
y = c(ymax, ymax, ymin, ymin, ymax),
x = c(xmin, xmax, xmax, xmin, xmin)
))
}

Note that this line also need to be adapted

aes <- new_data_frame(row[aesthetics])[rep(1,5), ]

@thomasp85
Copy link
Member

On that note I don't think it makes sense to add a lineend parameter to the geoms as they should be closed, while adding linejoin is sensible...

@yutannihilation can you update #3050 to create the correct polygon spec and remove lineend? I'm pretty sure it will break some visual tests, but it'll be more correct

@yutannihilation
Copy link
Member

whereas polygonGrob expect an open representation...

Opps, I didn't notice... Thanks, it makes sense. I will update so.

@thomasp85
Copy link
Member

It's a weird bug... probably a leftover from when the other representation made sense... recall anything @hadley ?

@karawoo
Copy link
Member

karawoo commented Jan 15, 2019

FYI it also seems to be inconsistent, I can't reproduce with the reprex provided

df <- expand.grid(x = 1:3, y = 1:3)
library("ggplot2")
ggplot(df) +
  geom_tile(aes(x = x, y = y),
            fill = NA, colour = "red", size = 3, width = 0.7, height = 0.7)

Created on 2019-01-15 by the reprex package (v0.2.1)

@ptoche
Copy link

ptoche commented Jan 15, 2019

I (too) get this:

plot

Specs summary:
ggplot2_3.1.0.9000
grid_3.5.2
gtable_0.2.0
R version 3.5.2 (2018-12-20) -- "Eggshell Igloo"
Platform: x86_64-apple-darwin15.6.0 (64-bit)

@DanielReedOcean
Copy link
Author

In response to the original SO question, someone else commented that they couldn't reproduce the issue on macOS either. @karawoo are you running on macOS, too?

@karawoo
Copy link
Member

karawoo commented Jan 15, 2019

Ah yes, I am

@yutannihilation
Copy link
Member

Curious. Visual tests pass even on my Windows, so I guess this is a problem on Windows' graphic device?

@yutannihilation
Copy link
Member

It seems we still need lineend even after fixing the polygon representation. Here's the result after 43eafa8:

library("ggplot2")

ggplot(data.frame(x = 1)) +
  geom_tile(aes(x, x),
            fill = NA, colour = "red", size = 10,
            width = 1, height = 1) +
  coord_equal()

Created on 2019-01-25 by the reprex package (v0.2.1)

@thomasp85
Copy link
Member

o_O - that does not make any sense at all... maybe this is a windows issue (assuming that you're on windows...

what do you get if you run:

grid::grid.rect(width = unit(.5, 'npc'), height = unit(0.5, 'npc'), gp = grid::gpar(lwd = 20, linejoin = 'mitre'))

@yutannihilation
Copy link
Member

Oh... Here's the result.

library(grid)
grid.rect(width = unit(.5, 'npc'), height = unit(0.5, 'npc'), gp = gpar(lwd = 20, linejoin = 'mitre'))

Created on 2019-01-25 by the reprex package (v0.2.1)

@thomasp85
Copy link
Member

ok, that is not what I get (i.e. I get even corners all around)

This is a grid bug (or even a windows device bug) - @pmur002 do you have any idea where this comes from..?

@yutannihilation
Copy link
Member

yutannihilation commented Jan 25, 2019

Hmm, thanks. Sorry that I haven't noticed this is the problem on Windows earlier...

@pmur002
Copy link
Contributor

pmur002 commented Jan 29, 2019

I see it (only on Windows). This appears to be a bug (or at least a poor design choice) in graphapp (that underlies the Windows device). graphapp's rectangle drawing draws a polyline, so what we are seeing is a line being drawn from the top-left corner around the perimeter of the rectangle. So the rounded top-left corner is round because of the rounded line start and end. You can work around the problem by specifying "square" lineend for the rectangle (which you should not have to do) - is that a possibility ? Code below shows what I mean for the simple grid.rect() demonstration

library(grid)
grid.rect(width = unit(.5, 'npc'), height = unit(0.5, 'npc'), gp = gpar(lwd = 20, linejoin = 'mitre', lineend = 'square'))

@yutannihilation
Copy link
Member

Thanks!

You can work around the problem by specifying "square" lineend for the rectangle (which you should not have to do) - is that a possibility?

I think it's possible, since we already specify lineend for rect (from the very beginning), we can just change this to "square".

lineend = "butt"

@yutannihilation
Copy link
Member

Ah, though we can use square lineend to imitate mitre linejoin,

  • For round linejoin, it's possible to use round, but this might make the implementation a bit complicated.
  • For babel linejoin, we don't have the corresponding lineend.

So, we have several choices:

  1. set linejoin = "mitre"and lineend = "square", and don't expose them as parameters
  2. expose linejoin as a parameter and set lineend = "square" fixedly
  3. expose linejoin as a parameter and set the corresponding lineend
  4. expose both lineend and linejoin as parameters

@yutannihilation
Copy link
Member

The problem is that the rectangles gets converted to polygons in closed form (first point gets repeated in the end), whereas polygonGrob expect an open representation...

@thomasp85 I think I found the reason why the polygons are in closed form...

2019-01-29 13 44 02

@lock
Copy link

lock bot commented Oct 28, 2019

This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/

@lock lock bot locked and limited conversation to collaborators Oct 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants