Skip to content
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

[FEATURE] Support FontAwesome Icons for Markers #60

Closed
5 tasks
rsh52 opened this issue Nov 5, 2024 · 8 comments · Fixed by #61
Closed
5 tasks

[FEATURE] Support FontAwesome Icons for Markers #60

rsh52 opened this issue Nov 5, 2024 · 8 comments · Fixed by #61
Assignees
Labels
enhancement New feature or request

Comments

@rsh52
Copy link
Contributor

rsh52 commented Nov 5, 2024

Feature Request Description

It would be nice to also allow for fontawesome icons in addition to shapes/glyphs and emojis. the fontawesome package does not currently seem capable of doing this, but emojifont might.

Additional Context

Here is an example output using geom_text and the emojifont package:

library(ggplot2)
library(emojifont)
library(dplyr)

df <- cars |> 
  mutate(
    label = case_when(speed > 16 ~ emojifont::fontawesome("fa-car"),
                      .default = emojifont::fontawesome("fa-bicycle"))
  )

ggplot() +
  geom_text(data = df,
            aes(x = speed, y = dist, label = label, colour = label),
            family = 'fontawesome-webfont', show.legend = TRUE) +
  theme(legend.text=element_text(family='fontawesome-webfont'))

image

Checklist

  • The issue is atomic
  • The issue description is documented
  • The issue title describes the problem succinctly
  • Developers are assigned to the issue
  • Labels are assigned to the issue
@rsh52 rsh52 added the enhancement New feature or request label Nov 5, 2024
@rsh52 rsh52 self-assigned this Nov 5, 2024
@skadauke
Copy link

skadauke commented Nov 6, 2024

A few comments here.

  • I noticed that emojifont uses a very old version of FA, v0.4, and the current version is 6.6. We should use 6.6 because it'll look a lot better.
  • emojifont packages the TTF font file from the fontawesome-free-web package that you can download from the FontAwesome website. It's in inst/fonts/. This appears to be OK by the SIL OFL 1.1 license which is very permissive in packaging fonts along with software, and it seems that as long as we don't modify the files and include the LICENSE.txt in the package we're good. This makes things easy and we should be able to just add the fonts we want to the ggswim package.
  • I believe geom_text() supports TTF only. The following TTF fonts are in the webfonts package. I think we should support regular and solid, not brands, and there's no need to provide compatibility with v4:
    • fa-brands-400.ttf
    • fa-regular-400.ttf <- include
    • fa-solid-900.ttf <- include
    • fa-v4compatibility.ttf
  • I don't think we need to support the "Pro" fonts.
  • If geom_text() is cumbersome (looks bad or positioning is difficult) we could also look into using PNG or SVG versions of these fonts, also available in the package.

@rsh52
Copy link
Contributor Author

rsh52 commented Nov 7, 2024

Did a little more investigating. Here's several options I've explored:

ggtext

{ggtext}'s geom_richtext() can support HTML and Albert Rapp goes through in his blog how to make this work, but I'm not sure yet if we can get away from extra setup on the users part to enable the fonts even after they're baked into the package.

library(tidyverse)
library(showtext)
library(ggtext)

# Import fonts
font_add(family = "fa-reg",
         regular = "inst/fontawesome/webfonts/fa-regular-400.ttf")
font_add('fa-brands', 'inst/fontawesome/webfonts/fa-brands-400.ttf')
font_add('fa-solid', 'inst/fontawesome/webfonts/fa-solid-900.ttf')

# Important step to enable showtext font rendering!
showtext_auto()

tibble(x = runif(25), y = runif(25)) %>% 
  ggplot(aes(x, y, label = "<span style='font-family:fa-solid;'>&#xf651;</span>")) +
  geom_richtext(size = 12, label.colour = NA, fill = NA, col = 'dodgerblue4',) +
  theme_minimal()

image

ggsvg / rsvg

Unfortunately {ggsvg} is not on CRAN, but it is a pretty simple way to take the fontawesome the SVG outputs supplied by the actual {fontawesome} package and put them in a ggplot pretty easily, requiring no file downloads on our part:

library(ggplot2)
library(rsvg)
library(ggsvg)

df <- data.frame(
  text = c("Hospital", "Hotel", "School"),
  icon = c(fontawesome::fa("hospital"), fontawesome::fa("hotel"), fontawesome::fa("school")),
  rank = c(1, 5, 10)
)

ggplot(data = df, mapping = aes(x = rank, y = text)) +
  geom_point_svg(aes(svg = icon), show.legend = FALSE)

image

Other downsides are coloring these and having them appear well in the legend are both non trivial.

emojifont

Example above and as you mentioned, a little outdated but plays well with geom_text() since geom_text() doesn't support HTML. Users just have to specify the font family argument and then check what's available (which is pretty easy to do with emojifont::search_fontawesome()).

I'm partial to this solution since it works directly with GeomText that we wrap and we already have methods in place to handle the legend output like we did with emojis.

I'm also opposed to this solution because while it is on CRAN it hasn't been actively worked on in 3+ years.

Evolving Thoughts

I think that in the end, we can point users to any of these solutions or we can look into opening up issues with packages like {fontawesome} with Rich Iannone's group to see if there's a better way to grab their outputs and have them mesh with ggplot2. I'm worried that doing too much to get this working innately in {ggswim} is outside the scope of the package itself, at least at this early stage. I can also ask the extenders group for any thoughts.

@skadauke
Copy link

skadauke commented Nov 7, 2024

I think it's totally fair to use {emojifont} code as a inspiration or a starting point and reimplement what it does in {ggswim}. Of course we'll acknowledge the author!

@rsh52
Copy link
Contributor Author

rsh52 commented Nov 7, 2024

I think it's totally fair to use {emojifont} code as a inspiration or a starting point and reimplement what it does in {ggswim}. Of course we'll acknowledge the author!

Ok I'll investigate a bit more, maybe open an issue to {emojifont} to see if they can update the FA version

@rsh52
Copy link
Contributor Author

rsh52 commented Nov 11, 2024

I'm 90% to having an implemented solution over on the fontawesome-dev branch:

library(ggplot2)
library(dplyr)
devtools::load_all()

df <- cars |>
  mutate(
    glyph = case_when(speed > 16 ~ fontawesome("fa-car"),
                      .default = fontawesome("fa-bicycle")),
    label = case_when(speed > 16 ~ "Fast",
                      .default = "Slow"),
    color = case_when(speed > 16 ~ "red",
                      .default = "green")
  ) |>
  tibble::tibble()

ggplot() +
  geom_swim_marker(
    data = df,
    aes(x = speed, y = dist, marker = label),
    size = 5, family = "fa"
  ) +
  scale_marker_discrete(glyphs = df$glyph,
                        colours = df$color,
                        limits = df$label)

image

The issue I'm running into is that once the font is loaded from our new setup, it masks or interferes with AGG device rendering for emojis, causing them to go back to appearing as empty rectangles or other aberrant text:

df <- cars |>
  mutate(
    glyph = case_when(speed > 16 ~ "",
                      .default = ""),
    label = case_when(speed > 16 ~ "Fast",
                      .default = "Slow"),
    color = case_when(speed > 16 ~ "red",
                      .default = "green")
  ) |>
  tibble::tibble()

ggplot() +
  geom_swim_marker(
    data = df,
    aes(x = speed, y = dist, marker = label),
    size = 5, family = "fa"
  ) +
  scale_marker_discrete(glyphs = df$glyph,
                        colours = df$color,
                        limits = df$label)

image

This is also the case when you simply call library(emojifont) in the same session. Can continue investigating, but wanted to give an update and see if anyone has thoughts @skadauke .

@rsh52
Copy link
Contributor Author

rsh52 commented Nov 13, 2024

Have found the real issue to be here:
yixuan/showtext#54

Trying to see if I can hack and identify what's going on.

@rsh52
Copy link
Contributor Author

rsh52 commented Nov 13, 2024

Solved! Did away with showtext, embraced systemfonts and this now works on the development branch. To tidy up and work on a bit more before merging to main and closing this. Here's a slick showcase of FA combined with emoji.

df <- cars |>
  mutate(
    glyph = case_when(speed > 16 ~ "",
                      .default = fontawesome("fa-car")),
    label = case_when(speed > 16 ~ "Fast",
                      .default = "Slow"),
    color = case_when(speed > 16 ~ "red",
                      .default = "green")
  ) |>
  tibble::tibble()

ggplot() +
  geom_swim_marker(
    data = df,
    aes(x = speed, y = dist, marker = label),
    size = 5, family = "FontAwesome"
  ) +
  scale_marker_discrete(glyphs = df$glyph,
                        colours = df$color,
                        limits = df$label)

image

@skadauke
Copy link

Cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants