1

My data looks like this:

d <- data.frame(X=c('x1','x2','x3','x1','x2','x3','x1','x2','x3'),
                Y=c('y1','y1','y1','y2','y2','y2','y3','y3','y3'),
                Value=c(1,2,1,3,1,4,3,5,2))

I use the following code to generate a heat map:

ggplot(d,aes(x=X,y=Y,fill=Value)) +
  geom_tile() +
  scale_fill_gradient2(low='green',mid='white',high='red',midpoint=3) +
  theme(axis.text.x = element_text(angle = 90),
        axis.text = element_text(size = 10),
        panel.background = element_blank()) +
  labs(x='',y='')

The graph is:

enter image description here

But, my whole data is around 500*500, so too many ticks on x axis and y axis so that the labels are impossible to recognize clearly. But I have to keep all the values.

So I want to use double x axis and double y axis. For example, the bottom x axis only keeps the lables x1, x3, x5... and the top x axis only keeps the labels x2, x4, x6.... Then I do the same to y axis. Then, the graph looks like:

enter image description here

I know scale_x_continuous and sec.axis might do this. But my x and y are discrete.

Could anyone help me so that the graph looks like the second one?

1 Answer 1

3

You are right than you can only use a secondary axis with continuous data. One solution is to convert your x and y values to continuous values for plotting (just use a sequence of integers), but save your discrete x and y values as vectors to use for labelling your axes.

Here I've assigned continuous values in a way that should be scalable to your larger, actual dataset. I've made key dataframes for x and y to match each unique discrete value with an integer, than merged these key dataframes with your original dataframe so each discrete x and y value is assigned a numeric value that you can use for plotting.

#create key dataframes to assign an integer to each x and y value
key.df.x <- data.frame(X = unique(d$X), x.num = (1:length(unique(d$X))))
key.df.y <- data.frame(Y = unique(d$Y), y.num = (1:length(unique(d$Y))))

#merge key dataframes with original data
d <- merge(d, key.df.x, by = "X", all.x = TRUE)
d <- merge(d, key.df.y, by = "Y", all.x = TRUE)

#make label vectors from original variable names
xlabels = unique(d$X)
ylabels = unique(d$Y)

#select odd numbered elements for primary labels, even for secondary labels
xlabels.primary <- xlabels[seq(1, length(xlabels), by = 2)]
xlabels.secondary <- xlabels[seq(2, length(xlabels), by = 2)]
ylabels.primary <- ylabels[seq(1, length(ylabels), by = 2)]
ylabels.secondary <- ylabels[seq(2, length(ylabels), by = 2)]

ggplot(d,aes(x = x.num, y = y.num,fill=Value)) + #plot using continuous data
  geom_tile() +
  scale_fill_gradient2(low='green',mid='white',high='red',midpoint=3) +
  theme(axis.text.x = element_text(angle = 90),
        axis.text = element_text(size = 10),
        panel.background = element_blank()) +
  # set primary axis breaks to odd numbers, label with ylabels.primary
  scale_y_continuous(breaks = seq(1, max(d$y.num), by = 2), labels = ylabels.primary,
  # set secondary axis breaks to even numbers, label with ylabels.secondary                    
                      sec.axis = dup_axis(breaks = seq(2, max(d$y.num), by = 2),
                                         labels = ylabels.secondary)) +
  scale_x_continuous(breaks = seq(1, max(d$x.num), by = 2), , labels = xlabels.primary,
                     sec.axis = dup_axis(breaks = seq(2, max(d$x.num), by = 2),
                                         labels = xlabels.secondary)) +
  labs(x='',y='')

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

This is brilliant! Thanks a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.