I'm sure there's a way to do this with base R graphics, which you used to make your plots. However, I find that the package ggplot2 makes this sort of thing much easier. In the example below, I've used the data you provided as a matrix, then
library(dplyr) # for mutate and tibble
library(reshape2) # for melt function
library(ggplot2) # for plotting
# Data as you provided
rownames = c("IGH_V4", "IGH_V2", "IGH_V8", "IGH_V7")
colnames = c(456, 654, 457, 345)
reads.m <- matrix(c(0,55,0,65,0,0,4,100,0,0,67,6,0,56,0,0),
nrow = 4, byrow = TRUE,
dimnames = list(rownames, colnames))
# Melt the matrix into the shape of a dataframe
reads.m <- melt(reads.m)
# Convert the matrix to a data frame (tibble is a type of data frame with
# some nice extra features
reads.df <- as_tibble(reads.m)
# Name the columns
names(reads.df) <- c("Sequence", "Clone", "Reads")
# Create a data frame called diluted with an extra column indicating its
# concentration
diluted.df <- mutate(reads.df, Concentration = "Diluted")
# Do the same for undiluted aka straight then add a clone to change the
# range of clones. Because clones are on the x-axis of your plot, having
# different ranges of data is what presents the problem you're trying to
# solve by aligning the plot axes.
straight.df <- mutate(reads.df,
Concentration = "Straight",
Reads = round(Reads*1.2))
straight.df <- bind_rows(straight.df, tibble(Sequence = NA,
Clone = 700,
Reads = 8,
Concentration = "Straight"))
# Concatenate the tables for the two dilutions.
reads.df <- bind_rows(diluted.df, straight.df)
# Sanity check
print(reads.df, n = nrow(reads.df))
# # A tibble: 33 x 4
# Sequence Clone Reads Concentration
# <fct> <dbl> <dbl> <chr>
# 1 IGH_V4 456 0 Diluted
# 2 IGH_V2 456 0 Diluted
# 3 IGH_V8 456 0 Diluted
# 4 IGH_V7 456 0 Diluted
# 5 IGH_V4 654 55 Diluted
# 6 IGH_V2 654 0 Diluted
# 7 IGH_V8 654 0 Diluted
# 8 IGH_V7 654 56 Diluted
# 9 IGH_V4 457 0 Diluted
# 10 IGH_V2 457 4 Diluted
# 11 IGH_V8 457 67 Diluted
# 12 IGH_V7 457 0 Diluted
# 13 IGH_V4 345 65 Diluted
# 14 IGH_V2 345 100 Diluted
# 15 IGH_V8 345 6 Diluted
# 16 IGH_V7 345 0 Diluted
# 17 IGH_V4 456 0 Straight
# 18 IGH_V2 456 0 Straight
# 19 IGH_V8 456 0 Straight
# 20 IGH_V7 456 0 Straight
# 21 IGH_V4 654 66 Straight
# 22 IGH_V2 654 0 Straight
# 23 IGH_V8 654 0 Straight
# 24 IGH_V7 654 67 Straight
# 25 IGH_V4 457 0 Straight
# 26 IGH_V2 457 5 Straight
# 27 IGH_V8 457 80 Straight
# 28 IGH_V7 457 0 Straight
# 29 IGH_V4 345 78 Straight
# 30 IGH_V2 345 120 Straight
# 31 IGH_V8 345 7 Straight
# 32 IGH_V7 345 0 Straight
# 33 NA 700 8 Straight
ggplot(reads.df, aes(x = Clone, y = Reads, fill = Concentration)) +
geom_col(width = 4) +
facet_grid(rows = vars(Concentration)) +
theme_bw() + # White background, rather than default grey
ylab("Reads")

ggplot(reads.df, aes(x = Clone, y = Reads, fill = Concentration)) +
geom_col(width = 5) +
facet_wrap(facets = vars(Concentration)) +
theme_bw() + # White background, rather than default grey
ylab("Reads")

Note: ggplot is returning a warning that looks like this:
# Warning messages:
# 1: position_stack requires non-overlapping x intervals
# 2: position_stack requires non-overlapping x intervals
This is the result of manually setting the width of geom_col. Without setting that width manually, the width of the columns is so narrow that that they are hard to read. Making them wider is not causing them to overlap, so we can ignore the warning.