{"id":13711037,"url":"https://github.com/eclarke/ggbeeswarm","last_synced_at":"2025-10-21T20:56:29.023Z","repository":{"id":25877383,"uuid":"29317622","full_name":"eclarke/ggbeeswarm","owner":"eclarke","description":"Column scatter / beeswarm-style plots in ggplot2","archived":false,"fork":false,"pushed_at":"2024-06-25T21:00:25.000Z","size":19787,"stargazers_count":539,"open_issues_count":14,"forks_count":31,"subscribers_count":10,"default_branch":"main","last_synced_at":"2024-10-29T21:28:19.652Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eclarke.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-01-15T20:51:04.000Z","updated_at":"2024-10-28T21:03:26.000Z","dependencies_parsed_at":"2023-02-10T18:30:16.135Z","dependency_job_id":"fa2fa5de-1f5d-4359-be21-a4fefcaf5624","html_url":"https://github.com/eclarke/ggbeeswarm","commit_stats":{"total_commits":259,"total_committers":14,"mean_commits":18.5,"dds":0.4555984555984556,"last_synced_commit":"3cf58a9658044413e60540bbe7690aade78cbcb1"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclarke%2Fggbeeswarm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclarke%2Fggbeeswarm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclarke%2Fggbeeswarm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclarke%2Fggbeeswarm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eclarke","download_url":"https://codeload.github.com/eclarke/ggbeeswarm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224528332,"owners_count":17326342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T23:01:03.768Z","updated_at":"2025-10-21T20:56:23.993Z","avatar_url":"https://github.com/eclarke.png","language":"R","funding_links":[],"categories":["Plot layers","R","ggplot"],"sub_categories":["Additional Plot Types"],"readme":"---\ntitle: \"Beeswarm-style plots with ggplot2\"\noutput: github_document\n---\n```{r setup, echo=FALSE, message=FALSE}\nknitr::opts_chunk$set(\n  fig.retina=2,\n  fig.width=6,\n  fig.height=4\n)\n```\n\n[![Build Status](https://travis-ci.org/eclarke/ggbeeswarm.svg?branch=master)](https://travis-ci.org/eclarke/ggbeeswarm)\n[![CRAN status](https://www.r-pkg.org/badges/version/ggbeeswarm)](https://cran.r-project.org/package=ggbeeswarm)\n\n## Introduction\nBeeswarm plots (aka column scatter plots or violin scatter plots) are a way of plotting points that would ordinarily overlap so that they fall next to each other instead. In addition to reducing overplotting, it helps visualize the density of the data at each point (similar to a violin plot), while still showing each data point individually.\n\n`ggbeeswarm` provides two different methods to create beeswarm-style plots using [ggplot2](http://ggplot2.org). It does this by adding two new ggplot geom objects:\n\n- `geom_quasirandom`: Uses a [van der Corput sequence](http://en.wikipedia.org/wiki/Van_der_Corput_sequence) or Tukey texturing (Tukey and Tukey \"Strips displaying empirical distributions: I. textured dot strips\") to space the dots to avoid overplotting. This uses [sherrillmix/vipor](https://github.com/sherrillmix/vipor).\n\n- `geom_beeswarm`: Uses the [beeswarm](https://cran.r-project.org/web/packages/beeswarm/index.html) library to do point-size based offset. \n\nFeatures: \n\n- Can handle categorical variables on the y-axis (thanks @smsaladi, @koncina)\n- Automatically dodges if a grouping variable is categorical and `dodge.width` is specified (thanks @josesho)\n\nSee the examples below.\n\n\n## Installation\n\nThis package is on CRAN so install should be a simple:\n```{r, eval=FALSE}\ninstall.packages('ggbeeswarm')\n```\n\nIf you want the development version from GitHub, you can do:\n\n```{r, eval=FALSE}\ndevtools::install_github(\"eclarke/ggbeeswarm\")\n```\n\n## Examples\nHere is a comparison between `geom_jitter` and `geom_quasirandom` on the `iris` dataset:\n```{r ggplot2-compare}\nset.seed(12345)\nlibrary(ggplot2)\nlibrary(ggbeeswarm)\n#compare to jitter\nggplot(iris,aes(Species, Sepal.Length)) + geom_jitter()\nggplot(iris,aes(Species, Sepal.Length)) + geom_quasirandom()\n```\n\n### geom_quasirandom()\n\nUsing `geom_quasirandom`:\n```{r ggplot2-examples}\n\n#default geom_quasirandom\nggplot(mpg,aes(class, hwy)) + geom_quasirandom()\n\n# With categorical y-axis\nggplot(mpg,aes(hwy, class)) + geom_quasirandom()\n\n# Some groups may have only a few points. Use `varwidth=TRUE` to adjust width dynamically.\nggplot(mpg,aes(class, hwy)) + geom_quasirandom(varwidth = TRUE)\n\n# Automatic dodging\nsub_mpg \u003c- mpg[mpg$class %in% c(\"midsize\", \"pickup\", \"suv\"),]\nggplot(sub_mpg, aes(class, displ, color=factor(cyl))) + geom_quasirandom(dodge.width=1)\n```\n\n#### Alternative methods\n`geom_quasirandom` can also use several other methods to distribute points. For example:\n```{r ggplot2-methods,tidy=TRUE}\nggplot(iris,aes(Species, Sepal.Length)) + geom_quasirandom(method='tukey') + ggtitle('Tukey texture')\nggplot(iris,aes(Species, Sepal.Length)) + geom_quasirandom(method='tukeyDense') + ggtitle('Tukey + density')\nggplot(iris,aes(Species, Sepal.Length)) + geom_quasirandom(method='frowney') + ggtitle('Banded frowns')\nggplot(iris,aes(Species, Sepal.Length)) + geom_quasirandom(method='smiley') + ggtitle('Banded smiles')\nggplot(iris,aes(Species, Sepal.Length)) + geom_quasirandom(method='pseudorandom') + ggtitle('Jittered density')\nggplot(iris,aes(Species, Sepal.Length)) + geom_beeswarm() + ggtitle('Beeswarm')\n```\n\n### geom_beeswarm()\n\nUsing `geom_beeswarm`:\n```{r ggplot2-beeswarm}\n\nggplot(iris,aes(Species, Sepal.Length)) + geom_beeswarm()\nggplot(iris,aes(Species, Sepal.Length)) + geom_beeswarm(side = 1L)\nggplot(mpg,aes(class, hwy)) + geom_beeswarm(size=.5)\n# With categorical y-axis\nggplot(mpg,aes(hwy, class)) + geom_beeswarm(size=.5)\n# Also watch out for points escaping from the plot with geom_beeswarm\nggplot(mpg,aes(hwy, class)) + geom_beeswarm(size=.5) + scale_y_discrete(expand=expansion(add=c(0.5,1)))\n\nggplot(mpg,aes(class, hwy)) + geom_beeswarm(size=1.1)\n\n\n# With automatic dodging\nggplot(sub_mpg, aes(class, displ, color=factor(cyl))) + geom_beeswarm(dodge.width=0.5)\n```\n\n#### Alternative methods\n\n```{r ggplot2-beeswarm-alt}\ndf \u003c- data.frame(\n  x = \"A\",\n  y = sample(1:100, 200, replace = TRUE)\n)\nggplot(df, aes(x = x, y = y)) + geom_beeswarm(cex = 2.5, method = \"swarm\") + ggtitle('method = \"swarm\" (default)')\nggplot(df, aes(x = x, y = y)) + geom_beeswarm(cex = 2.5, method = \"compactswarm\") + ggtitle('method = \"compactswarm\"')\nggplot(df, aes(x = x, y = y)) + geom_beeswarm(cex = 2.5, method = \"hex\") + ggtitle('method = \"hex\"')\nggplot(df, aes(x = x, y = y)) + geom_beeswarm(cex = 2.5, method = \"square\") + ggtitle('method = \"square\"')\nggplot(df, aes(x = x, y = y)) + geom_beeswarm(cex = 2.5, method = \"center\") + ggtitle('method = \"center\"')\n```\n\n#### Different point distribution priority\n\n```{r ggplot2-priority}\n#With different beeswarm point distribution priority\ndat\u003c-data.frame(x=rep(1:3,c(20,40,80)))\ndat$y\u003c-rnorm(nrow(dat),dat$x)\nggplot(dat,aes(x,y)) + geom_beeswarm(cex=2) + ggtitle('Default (ascending)') + scale_x_continuous(expand=expansion(add=c(0.5,.5)))\nggplot(dat,aes(x,y)) + geom_beeswarm(cex=2,priority='descending') + ggtitle('Descending') + scale_x_continuous(expand=expansion(add=c(0.5,.5)))\nggplot(dat,aes(x,y)) + geom_beeswarm(cex=2,priority='density') + ggtitle('Density') + scale_x_continuous(expand=expansion(add=c(0.5,.5)))\nggplot(dat,aes(x,y)) + geom_beeswarm(cex=2,priority='random') + ggtitle('Random') + scale_x_continuous(expand=expansion(add=c(0.5,.5)))\n```\n\n#### Corral runaway points\n\n```{r ggplot2-corral}\nset.seed(1995)\ndf2 \u003c- data.frame(\n  y = rnorm(1000),\n  id = sample(c(\"G1\", \"G2\", \"G3\"), size = 1000, replace = TRUE)\n)\np \u003c- ggplot(df2, aes(x = id, y = y, colour = id))\n\n# use corral.width to control corral width\np + geom_beeswarm(cex = 2.5, corral = \"none\", corral.width = 0.9) + ggtitle('corral = \"none\" (default)')\np + geom_beeswarm(cex = 2.5, corral = \"gutter\", corral.width = 0.9) + ggtitle('corral = \"gutter\"')\np + geom_beeswarm(cex = 2.5, corral = \"wrap\", corral.width = 0.9) + ggtitle('corral = \"wrap\"')\np + geom_beeswarm(cex = 2.5, corral = \"random\", corral.width = 0.9) + ggtitle('corral = \"random\"')\np + geom_beeswarm(cex = 2.5, corral = \"omit\", corral.width = 0.9) + ggtitle('corral = \"omit\"')\n```\n\n\n------\nAuthors: Erik Clarke, Scott Sherrill-Mix, and Charlotte Dawson\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclarke%2Fggbeeswarm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feclarke%2Fggbeeswarm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclarke%2Fggbeeswarm/lists"}