How to Add Images to ggplot Axes Using ggtext::element_markdown()

A practical guide for adding logos, icons, and flags to your plots

ggtext
ggplot
R-Hacks
Author

Lucio Colonna

Published

November 19, 2025

This tip is based on a full Kaggle notebook, where this technique is applied in a complete Exploratory Data Analysis (EDA): πŸ”— https://www.kaggle.com/code/lcolon/football-2023-2024-eda-and-pa-with-logos

Have you ever needed to show logos, icons, or flags directly on the axes of your ggplot charts?

You can do this using the element_markdown() function from the {ggtext} package!

element_markdown() is a function that tells ggplot to treat labels as HTML instead of plain text. It must be used in the theme() section of your ggplot code.

The chart below shows an example where league logos appear directly on the x-axis. It displays the total number of goals scored in the major European football leagues during the 2023/2024 season:

European football leagues 2023/2024

Exploratory Data Analysis Workflow

Here is a short, practical guide showing how to recreate this plot.

Step 0: Start from a basic dataframe

In most real situations you will already have a dataframe to work with. Here is the one used in this example:

df <- data.frame(
  league = c("Premier League", "La Liga", 
             "Serie A", "Bundesliga", "Ligue 1"),
  goals  = c(1197, 977, 968, 960, 804))

df
          league goals
1 Premier League  1197
2        La Liga   977
3        Serie A   968
4     Bundesliga   960
5        Ligue 1   804

Step 2: Add a column with HTML tags

In order to display images on the axis, each image URL must be wrapped inside an HTML tag. This simply means that the URL cannot appear alone β€” it must be placed inside the structure:

`<img src= + image_url + width='45'/>`

Please note that in this example I use width=β€˜45’ just as a reference size, but you can choose any value depending on how big you want the image to appear in your plot.

Let’s add the column to the df:

df$logo <- c(
  paste0("<img src='", premier_url, "' width='45'/>"), 
  paste0("<img src='", laliga_url, "' width='45'/>"), 
  paste0("<img src='", seriea_url, "' width='45'/>"), 
  paste0("<img src='", bundes_url, "' width='45'/>"), 
  paste0("<img src='", ligue1_url, "' width='45'/>")
  )

At this point, the dataframe should look like this:


league goals logo
Premier League 1197 <img src='https://upload.wikimedia.org/wikipedia/it/6/6d/Premier_League_Logo_2016.png' width='45'/>
La Liga 977 <img src='https://upload.wikimedia.org/wikipedia/it/9/9b/LFP_La_Liga.png' width='45'/>
Serie A 968 <img src='https://www.fifplay.com/img/public/serie-a-logo.png' width='45'/>
Bundesliga 960 <img src='https://www.fifplay.com/img/public/bundesliga-logo.png' width='45'/>
Ligue 1 804 <img src='https://upload.wikimedia.org/wikipedia/commons/a/a0/Ligue_1_2024_Logo.png' width='45'/>


Step 3: Plot your data!

Now that the dataframe contains a column of HTML tags, we can use it directly on the x-axis. The key part is here:

theme( axis.text.x = element_markdown() )

element_markdown() function is what allows ggplot to interpret the HTML in your axis labels. Without it, ggplot would show the literal string <img src='...'> as plain text. With it, the <img> tags are rendered as actual images.

Here is the full plotting code:

options(repr.plot.width = 6, 
        repr.plot.height = 7, 
        warn = -1)
ggplot(df, 
       aes(x = reorder(logo, -goals), y = goals)) + 
  geom_col(fill = "forestgreen", width = .8) +
  geom_text(aes(label = goals), vjust = -0.5, size = 4.5) + 
  labs(title = "\nFootball stats 2023/2024",
       subtitle = "Total Goals scored in each League\n" ) + 
  theme_minimal(14) +
  # HTML rendering happens here!!
  theme(axis.text.x = ggtext::element_markdown(), 
         axis.text.y = element_blank(), 
         panel.grid = element_blank(), 
         axis.title = element_blank(), 
         plot.title = element_text(face = "bold", 
                                   colour = "blue", hjust = 0.05), 
         plot.subtitle= element_text(hjust = 0.05)
         )

With element_markdown() applied to axis.text.x, ggplot correctly displays the league logos instead of plain text labels, as seen in the barchart above.

To Recap

  1. Prepare your dataframe (existing or new)
  2. Choose your images (PNG recommended) and store their URLs
  3. Wrap each URL inside an HTML tag with a defined width
  4. Add this HTML column to your dataframe
  5. Map it to the ggplot axis
  6. Enable HTML rendering in plot theme using:
axis.text.x = ggtext::element_markdown()

Thanks for reading!

Tip

If you want to stay up to date with the latest events from the Rome R Users Group, click here:
πŸ‘‰https://www.meetup.com/rome-r-users-group/

And if you are curious, the full Kaggle notebook used for this tip is available here: πŸ”—https://www.kaggle.com/code/lcolon/football-2023-2024-eda-and-pa-with-logos

Back to top