Overlay Grid Rather Than Draw on Top of It

Overlay grid rather than draw on top of it

ggplot introduced an option in theme() that lets you do just that with pull number 993, on June 18, 2015.

Just add to your plot:

+ theme(
panel.background = element_rect(fill = NA),
panel.ontop = TRUE
)

There is an example in the ggplot docs.

Overlay grid on coloured panel background and different coloured rectangle

In ggplot, the panel background & grid layers are contained within the same grob. So either both stay below the geom layers (default panel.ontop = FALSE) or both go over them (panel.ontop = TRUE). Here are two possible workarounds for consideration:

  1. Use panel.ontop = TRUE, keep panel background transparent, and colour the entire plot background with your desired colour instead:
ggplot(df) +
geom_rect(xmin=2,xmax=3,ymin=-Inf,ymax=Inf,fill="gray") +
geom_line(aes(x=t,y=a),colour="red") +
geom_line(aes(x=t,y=b),colour="blue")+

theme(plot.background = element_rect(fill = "lightblue"), # change this line to plot.background
panel.background = element_rect(fill = NA),
panel.ontop = TRUE,
panel.grid.minor=element_line(colour="hotpink",size=0.5),
panel.grid.major=element_line(colour="green",size=0.5))

1st approach


  1. Leave default panel.ontop = FALSE, then hack the underlying grobs to move the grid lines to the top:
p <- ggplot(df) +
geom_rect(xmin=2,xmax=3,ymin=-Inf,ymax=Inf,fill="gray") +
geom_line(aes(x=t,y=a),colour="red") +
geom_line(aes(x=t,y=b),colour="blue")+

theme(panel.background = element_rect(fill = "lightblue"),
panel.grid.minor=element_line(colour="hotpink",size=0.5),
panel.grid.major=element_line(colour="green",size=0.5))

# convert from ggplot object to grob object
gp <- ggplotGrob(p)

# make a copy of the grob that contains the panel background (first child) & panel grids (all subsequent children),
# then drop the panel background grob (i.e. only keep the grobs for grids)
panel.grid.grob <- gp$grobs[[6]]$children[[1]]
panel.grid.grob$children[[1]] <- zeroGrob()

# leave only the panel background grob in its original slot
gp$grobs[[6]]$children[[1]] <- gp$grobs[[6]]$children[[1]]$children[[1]]

# add back grid grobs on top of panel
gp <- gtable::gtable_add_grob(gp, panel.grid.grob, t = 7, l = 5)

# plot result
grid::grid.draw(gp)

2nd approach

The first approach is simpler to implement, but the panel background colour would 'spill out' over the entire plot, including the axes labels. You may find one or the other more useful, depending on your use case.

R - put ggplot grid lines in foreground

As @joran suggested, using geom_hline and geom_vline is defenitely a solution. Simple define the yintercept and xintercept respectively like so:

...
+ geom_vline(xintercept=seq(7.08, 7.14, by=0.01))
+ geom_hline(yintercept=seq(50.93, 50.96, by=0.01))
...

How to draw grid on top of one geom but not another

It isn't really possible to move the panel grid over some geoms but not others (at least not without rendering the ggplot and hacking the underlying grobs).

However, the obvious workaround is to make the grid with hline and vline geoms:

library(ggridges)
library(tidyverse)

ggplot(iris, aes(x = Sepal.Length, y = Species)) +
geom_rect(xmin = 4, xmax = 7, ymin = 1, ymax = 6,
fill = '#d6d6d6') +
geom_hline(aes(yintercept = Species), color = "gray70") +
geom_vline(data = data.frame(Sepal.Length = 4:8),
aes(xintercept = Sepal.Length),
color = "gray70") +
geom_density_ridges() +
theme_ridges()

Sample Image

Matplotlib - How to overlay a grid on a different axes over an image?

You can set the background of your grid to be transparent with the set_alpha command, similar to the answer to the question at How to set opacity of background colour of graph wit Matplotlib

ax1 = fig.add_subplot(111)
ax1.grid()
ax1.patch.set_alpha(0)

draw grid lines over an image in matplotlib

You will need the python imaging library (PIL) installed. (See here https://pypi.python.org/pypi/PIL). See these answers for examples of ways to install PIL: answer 1, answer 2

Right, with that installed, the following code should do what you ask for:

import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
try:
from PIL import Image
except ImportError:
import Image

# Open image file
image = Image.open('myImage.tiff')
my_dpi=300.

# Set up figure
fig=plt.figure(figsize=(float(image.size[0])/my_dpi,float(image.size[1])/my_dpi),dpi=my_dpi)
ax=fig.add_subplot(111)

# Remove whitespace from around the image
fig.subplots_adjust(left=0,right=1,bottom=0,top=1)

# Set the gridding interval: here we use the major tick interval
myInterval=100.
loc = plticker.MultipleLocator(base=myInterval)
ax.xaxis.set_major_locator(loc)
ax.yaxis.set_major_locator(loc)

# Add the grid
ax.grid(which='major', axis='both', linestyle='-')

# Add the image
ax.imshow(image)

# Find number of gridsquares in x and y direction
nx=abs(int(float(ax.get_xlim()[1]-ax.get_xlim()[0])/float(myInterval)))
ny=abs(int(float(ax.get_ylim()[1]-ax.get_ylim()[0])/float(myInterval)))

# Add some labels to the gridsquares
for j in range(ny):
y=myInterval/2+j*myInterval
for i in range(nx):
x=myInterval/2.+float(i)*myInterval
ax.text(x,y,'{:d}'.format(i+j*nx),color='w',ha='center',va='center')

# Save the figure
fig.savefig('myImageGrid.tiff',dpi=my_dpi)

Which, if used on the grace_hopper.png example file, produces the following output:

Image with numbered grid

Overlay grid onto QFrame

Put the QFrame into a QGridLayout, then put a custom QWidget with transparent background and paintEvent that paints the grid on top of it (same QGridLayout position).

Or since you already have a QGridLayout, just put the custom QWidget in that, above the tiles, filling the entire grid.


A side note, are you sure you want QFrame there, or if just QWidget would do? Just saying, because with QFrame you get that 1990's look into your UI... If you do want that then go ahead, just saying.

Overlay grid on responsive image

Using two linear-gradients on pseudo-elements of the div, one on ::before and one on ::after, we can create two simple lines which are then repeated every nth-percent with background-size. The ::after pseudo-element is rotated 90deg to create the horizontal lines. It looks like this:

.grid::before,
.grid::after {
background: linear-gradient(to right, #000 2px, transparent 2px);
background-size: 10%;
}

.grid::after {
transform: rotate(90deg);
}

The two gradients create two intersecting lines which are a percentage size long, like this:

The grid lines

These lines are repeated with the default background-repeat: repeat, which creates a grid, like this:

The grid

When the ::before and ::after pseudo elements are placed over the image we get this:

Result

You can create a fixed grid size, using a fixed pixel background-size:

.fixed::before,
.fixed::after {
background-size: 23px;
}

Example

Note how the entire grid is given an outline using box-shadow: inset 0px 0px 0 2px #000; on ::before.



*,

*::before,

::after {

margin: 0;

padding: 0;

box-sizing: border-box;

}

.grid img {

display: block;

}

.grid {

display: inline-block;

position: relative;

margin: 10px;

vertical-align: top;

}

.grid::before,

.grid::after {

content: '';

position: absolute;

top: 0;

left: 0;

width: 100%;

height: 100%;

background: linear-gradient(to right, #000 2px, transparent 2px);

background-size: 10%;

}

.grid::before {

background-color: rgba(255, 0, 0, 0.56);

box-shadow: inset 0px 0px 0 2px #000;

}

.grid::after {

transform: rotate(90deg);

}

.fixed::before,

.fixed::after {

background-size: 23px;

}
<div class="grid">

<img src="https://dummyimage.com/300x300/ccc" width="300" height="300" />

</div>

<div class="grid">

<img src="https://dummyimage.com/200x200/ccc" width="200" height="200" />

</div>

<div class="grid">

<img src="https://dummyimage.com/100x100/ccc" width="100" height="100" />

</div>

<div class="grid fixed">

<img src="https://dummyimage.com/500x500/ccc" width="500" height="500" />

</div>

Bar graph groups on top of each other rather than superimposing each other

You can adjust the position of groups in geom_bar with the argument position:

geom_bar(stat = "identity", position = position_dodge())

I believe there is no need to use the argument group in ggplot(aes())

If you want to change the color of all bar instead of the outline, change color by fill



Related Topics



Leave a reply



Submit