5

I would like to use a custom font in my shiny app (on plots) on shinyapps.io. I have my Roboto-Regular.ttf in the ./www/ directory. And this is the upper portion of my app.R file:

dir.create('~/.fonts')
system("chmod +x ./www/Roboto-Regular.ttf")
system("cp ./www/Roboto-Regular.ttf ~/.fonts/")
system('fc-cache -f -v ~/.fonts/')
system('fc-match Roboto')

library(ggplot2)
library(shiny)
library(shinythemes)

library(extrafont)
font_import(pattern="Roboto",prompt=FALSE)
loadfonts()
print(fonts())

Upon deploying the app, I end up with an error that looks like this:

Registering fonts with R
Scanning ttf files in /usr/share/fonts/, ~/.fonts/ ...
Extracting .afm files from .ttf files...
/home/shiny/.fonts/Roboto-Regular.ttfWarning in gzfile(dest, "w") :
  cannot open compressed file '/opt/R/3.5.1/lib/R/library/extrafontdb/metrics/Roboto-Regular.afm.gz', probable reason 'Permission denied'
Error in value[[3L]](cond) : cannot open the connection
Calls: local ... tryCatch -> tryCatchList -> tryCatchOne -> <Anonymous>
Execution halted

Does anyone see what might be wrong?

mindlessgreen
  • 11,059
  • 16
  • 68
  • 113

3 Answers3

9

After a bit of struggle I found an even simpler solution that works on shinyapps.io:

Here we go:

  1. Place custom font in www directory: e.g. IndieFlower.ttf from here
  2. Follow the steps from here

This leads to the following upper part of the app.R file:

dir.create('~/.fonts')
file.copy("www/IndieFlower.ttf", "~/.fonts")
system('fc-cache -f ~/.fonts')

Since Linux looks into the .fonts directory to search fonts, you don't need the extrafont package, but you can directly use those fonts like:

ggplot(mapping=aes(x=seq(1,10,.1), y=seq(1,10,.1))) +
      geom_line(position="jitter", color="red", size=2) + theme_bw() +
      theme(text=element_text(size = 16, family = "IndieFlower"))
symbolrush
  • 7,123
  • 1
  • 39
  • 67
2

This is the answer I received from RStudio regarding this. I haven't tested this out myself.

Hi,

Our developer was able to advise this is due to a possibly unfortunate design choice made when they created extrafont and the associated extrafontdb package. The extrafont font database is stored in the extrafontdb package directory -- that's essentially all that the extrafontdb package is used for.

This means that the extrafontdb directory needs to be user-writable. If the user installs the package, this will work fine, but if root installs the package (as is the case on shinyapps.io), then it won't work.

One potential workaround is to install the extrafontdb package to library that is in subdirectory of the app.

To do it: create an r-lib/ subdir, and download the extrafontdb source package there:

dir.create('r-lib')
download.file('https://cran.r-project.org/src/contrib/extrafontdb_1.0.tar.gz','r-lib/extrafontdb_1.0.tar.gz')

When deployed, the app will include this r-lib/ subdirectory and the extrafontdb source package.

Then, at the top of the app, install the extrafontdb package from the source package, into the r-lib directory.

.libPaths(c('r-lib', .libPaths()))
install.packages('r-lib/extrafontdb_1.0.tar.gz',type = 'source',repos = NULL)

They deployed an app on shinyapps.io that does the extrafontdb installation, and it works fine. The libpath is set so so that install.packages() will install from the provided source package to the r-lib/ subdirectory of the app.

Please let us know if you're able to implement the above or have any additional questions.

Thanks,

mindlessgreen
  • 11,059
  • 16
  • 68
  • 113
  • Thanks for posting this. I think I got closer.. But it it still doesn't work for me. See my question [here](https://stackoverflow.com/questions/55100069/ggplot-with-customized-font-not-showing-properly-on-shinyapps-io) – symbolrush Mar 11 '19 at 10:50
0

Adding an alternative answer to symbolrush's answer which I found did not work. Here was the code I used initially:

# Add fonts to shiny linux server
if (Sys.info()[['sysname']] == 'Linux') {
    dir.create('~/.fonts')
fonts = c(
    "www/IBMPlexSans-Regular.ttf",
    "www/IBMPlexSans-Bold.ttf",
    "www/IBMPlexSans-Medium.ttf"
    )
file.copy(fonts, "~/.fonts")
system('fc-cache -f ~/.fonts')
}

# Load fonts and set theme
font_paths("fonts")

font_add("IBMPlexSans", regular = "IBMPlexSans-Regular.ttf")
font_add("IBMPlexSans-Bold", regular = "IBMPlexSans-Bold.ttf")
font_add("IBMPlexSans-Medium", regular = "IBMPlexSans-Medium.ttf")
showtext_auto()

The bizarre thing is that the first instance of the app on shinyapps.io worked, including the custom fonts. However when the app went to sleep and was opened a second time, I get this error in the log:

Error in value[[3L]](cond) : font file not found for 'regular' type

I was never able to debug why this was the case, but I tried a simpler solution that has worked perfectly so far. I moved my fonts to a /font folder in the app folder (I don't think using the /www folder is necessary) and added the /font folder using path_folder():

library(showtext)
# Load fonts and set theme
font_paths("fonts")

font_add("IBMPlexSans", regular = "IBMPlexSans-Regular.ttf")
font_add("IBMPlexSans-Bold", regular = "IBMPlexSans-Bold.ttf")
font_add("IBMPlexSans-Medium", regular = "IBMPlexSans-Medium.ttf")
showtext_auto()

I hope this helps anyone who is having problems with their app not running after the first instance, as I could not find the same situation anywhere on stackoverflow.

SpikyClip
  • 154
  • 10