www.eamoncaddigan.net

Content and configuration for https://www.eamoncaddigan.net
git clone https://git.eamoncaddigan.net/www.eamoncaddigan.net.git
Log | Files | Refs | Submodules | README

index.Rmd (5257B)


      1 ---
      2 title: "Web viewports"
      3 author: "Eamon Caddigan"
      4 date: "2023-08-21T21:07:47-07:00"
      5 lastmod: "2023-08-22T08:58:51-07:00"
      6 draft: False
      7 categories:
      8 - Programming
      9 - Data Science
     10 tags:
     11 - Design
     12 output: 
     13   md_document:
     14     variant: markdown
     15     preserve_yaml: true
     16 ---
     17 
     18 ```{r setup, include=FALSE}
     19 knitr::opts_chunk$set(echo = FALSE,
     20                       fig.width = 5.5,
     21                       fig.height = 3,
     22                       dpi = 150,
     23                       fig.path = "")
     24 ```
     25 
     26 Andy Bell from [Set Studio](https://set.studio/) shared [the outcome of a study
     27 of browser viewport sizes](https://viewports.fyi/); the area of the screen
     28 (measured in pixels) available for web pages. They shared the data so I thought
     29 I'd take a quick look at it.
     30 
     31 ```{r packages}
     32 suppressPackageStartupMessages(library(readr))
     33 suppressPackageStartupMessages(library(dplyr))
     34 suppressPackageStartupMessages(library(purrr))
     35 suppressPackageStartupMessages(library(broom))
     36 suppressPackageStartupMessages(library(ggplot2))
     37 ```
     38 
     39 ```{r load-data, cache=TRUE}
     40 viewports <- suppressMessages(read_csv("https://viewports.fyi/data.csv",
     41                                        col_types = cols(
     42                                          Width = col_double(),
     43                                          Height = col_double(),
     44                                          Count = col_double(),
     45                                          ...4 = col_character()
     46                                        ))) |>
     47   mutate(Height = abs(Height),
     48          aspect_ratio = Width / Height,
     49          area = Width * Height)
     50 ```
     51 
     52 First let's check the distribution of aspect ratios. With mobile browsing more
     53 popular than desktop, I expect tall displays to dominate the wide ones, but what
     54 do the data say?
     55 
     56 ```{r plot-aspect-ratio, warning=FALSE}
     57 ggplot(viewports, aes(aspect_ratio)) +
     58   geom_density(aes(weight = Count)) +
     59   scale_x_log10(breaks = c(1/3, 9/16, 1, 16/9, 3/1),
     60                 labels = c("1:3", "9:16", "1:1", "16:9", "3:1")) +
     61   coord_cartesian(xlim = c(1/4, 4/1)) +
     62   theme(panel.background = element_blank(),
     63         panel.grid = element_blank(),
     64         axis.text.y = element_blank(),
     65         axis.ticks.y = element_blank(),
     66         axis.title = element_blank(),
     67         axis.text.x = element_text(size = 14),
     68         axis.ticks.x = element_line(linewidth = 1),
     69         plot.title = element_text(size = 16)) +
     70   labs(title = "Distribution of viewport aspect ratios")
     71 ```
     72 
     73 As expected, tall (narrow) displays dominate the distribution, bu the peak also
     74 seems sharper. This isn't surprising; phone screens come in a few discrete
     75 sizes, and for each phone screen, there is a small number of viewports (but,
     76 importantly, more than one) associated with each one.
     77 
     78 How do the distribution of height and width relate to each other? I'll plot a
     79 point for each unique viewport, and set the alpha value of each point to the
     80 number of observations of that specific size. Points above and to the left of
     81 the dashed line are taller than they are wide (i.e., "portrait mode"), and those
     82 below and to its right are wider than tall ("landscape mode"). We confirmed that
     83 tall viewports are the most common by looking at aspect ratios, but how are the
     84 specific sizes distributed?
     85 
     86 ```{r plot-height-width}
     87 ggplot(viewports, aes(x = Width, y = Height)) +
     88   geom_point(aes(alpha = Count)) +
     89   geom_abline(slope = 1, intercept = 0, linetype = "dashed", linewidth = 0.5) +
     90   scale_x_log10() +
     91   scale_y_log10() +
     92   theme_minimal() +
     93   theme(axis.title = element_text(size = 14),
     94         axis.text = element_text(size = 12)) +
     95   labs(x = "Viewport width",
     96        y = "Viewport height")
     97 ```
     98 
     99 I feel like my eye detects three clusters of height-by-width combinations, but
    100 k-means is clustering these unreliably—sometimes the "small wide" viewports get
    101 clustered alone together, and sometimes they're grouped with the "small tall"
    102 viewports. This suggests that three (and also four—I checked) clusters don't
    103 describe these data particularly well.
    104 
    105 However, taking these two graphics together, we can see that while tall displays
    106 tend to be smaller than wide ones in general (which is what we may expect,
    107 knowing that mobile browsers are more prevalent than desktop browsers), there
    108 are plenty of exceptions in the data set which should be considered during
    109 design.
    110 
    111 I think there's more to look at here, and I'll update this if I find anyting
    112 interesting!
    113 
    114 ```{r cluster-viewports, include=FALSE}
    115 viewports_long <- viewports |>
    116   mutate(log_width = log(Width),
    117          log_height = log(Height)) |>
    118   map_dfc(~ rep(.x, times = viewports$Count))
    119 viewports_clust <- kmeans(viewports_long[, c("Width", "Height")], 4)
    120 viewports_long <- augment(viewports_clust,
    121                           viewports_long)
    122 viewports <- distinct(viewports_long)
    123 ```
    124 
    125 ```{r plot-clusters, include=FALSE}
    126 ggplot(viewports_long, aes(Width, Height)) +
    127   geom_point(aes(alpha = Count, color = .cluster)) +
    128   geom_abline(slope = 1, intercept = 0, linetype = "dashed", linewidth = 0.5) +
    129   scale_x_log10() +
    130   scale_y_log10() +
    131   scale_color_brewer(palette = "Paired") +
    132   theme_minimal() +
    133   theme(axis.title = element_text(size = 14),
    134         axis.text = element_text(size = 12)) +
    135   labs(x = "Viewport width",
    136        y = "Viewport height")
    137 ```