Coder Social home page Coder Social logo

ggarrow's Introduction

ggarrow

Lifecycle: experimental R-CMD-check Codecov test coverage CRAN status

The goal of ggarrow is to draw arrows in {ggplot2}. It is a {ggplot2} extension package that focusses on specialised geometry layers to expand the toolkit of arrows.

Installation

You can install ggarrow from CRAN

install.packages("ggarrow")

You can install the development version of ggarrow from GitHub with:

# install.packages("devtools")
devtools::install_github("teunbrand/ggarrow")

Arrows

They’re made for pointing at things. The workhorse functionality is in the geom_arrow() function that, unsurprisingly, draws arrows.

Basic arrows

library(ggarrow)
#> Loading required package: ggplot2

p <- ggplot(whirlpool(5), aes(x, y, colour = group)) +
  coord_equal() +
  guides(colour = "none")
p + geom_arrow()

Variable width

Arrows, in contrast to vanilla lines, can have variable widths.

p + geom_arrow(aes(linewidth = I(arc))) # Identity scale for linewidth

Inner arrows

Besides varying linewidths, there is also an option to place arrows along the path. You could draw arbitrarily many of these, but I doubt that will look pretty.

p + geom_arrow(arrow_mid = "head_wings", mid_place = c(0.25, 0.5, 0.75))

Ornament styles

You can also tweak what the arrows should look like. The example below is a bit verbose, but gives an impression of the available options by combining different styles of arrow heads and what are termed ‘arrow fins’.

p + geom_arrow(aes(arrow_head = group, arrow_fins = group), linewidth = 2) +
  scale_arrow_head_discrete(values = list(
    "head_wings",
    arrow_head_wings(offset = 20, inset = 70),
    arrow_head_line(lineend = "parallel"),
    arrow_head_line(45, lineend = "round"),
    "head_minimal"
  ), guide = "none") +
  scale_arrow_fins_discrete(values = list(
    "fins_feather",
    arrow_fins_feather(indent = 0, outdent = 0, height = 1),
    "fins_line",
    arrow_fins_line(90),
    "fins_minimal"
  ), guide = "none")

There are some other geoms that mimic bread-and-butter ggplot2 layers, such as geom_arrow_segment() and geom_arrow_curve(), that add the same arrow functionality on top of the geom_segment() and geom_curve() layers.

Chains

Aside from these, there is also geom_arrow_chain(), which has no equivalent in vanilla ggplot2. It adds arrows in between points, and dodges the endpoints a bit so that they don’t seem to touch. In the example below, we can see that we can dodge points of different sizes.

t <- seq(0, 2 * pi, length.out = 11)
l <- rep(c(1, 0.4), length.out = 11)

df <- data.frame(
  x = cos(t) * l,
  y = sin(t) * l,
  size = l
)

ggplot(df, aes(x, y, size = size)) +
  geom_point(colour = 2) +
  geom_arrow_chain() +
  coord_equal()

Theme elements

Because arrows are almost drop-in replacements for lines, I also included element_arrow() as a theme element. With function, you can set any line element in the theme to an arrow, with similar customisation options as the layers.

p + geom_arrow() +
  theme(
    axis.line.x = element_arrow(
      arrow_head = "head_wings", linewidth_head = 1.5, linewidth_fins = 0
    ),
    axis.line.y = element_arrow(arrow_head = "head_line"),
    axis.ticks.length = unit(0.4, "cm"),
    axis.ticks.x = element_arrow(linewidth_fins = 0, linewidth_head = 2),
    axis.ticks.y = element_arrow(arrow_fins = "head_line"),
    panel.grid.major = element_arrow(
      linewidth_head = 5, linewidth_fins = 0,
      resect_head = 5, resect_fins = 5, lineend = "round"
    ),
    panel.grid.minor = element_arrow(
      linewidth_head = 0, linewidth_fins = 5
    )
  )

Limitations

The current limitation is that variable width paths don’t lend themselves well to jagged paths with short segments. This is because I had to implement linejoins for variable width paths and I barely have high-school level understanding of trigonometry. Consequently, the linejoins look bad with short jagged segments.

ggplot(economics, aes(date, unemploy)) +
  geom_arrow(aes(linewidth = date))

The best advice I can give for the jagged linejoins is to smooth the data beforehand.

ggplot(economics, aes(date, unemploy)) +
  geom_arrow(
    stat = "smooth", formula = y ~ x, method = "loess", span = 0.05,
    aes(linewidth = after_stat(x))
  )

A second limitation is that you cannot use variable widths with different linetypes.

Dependency statement

The {ggarrow} package largely takes on the same dependencies as {ggplot2} to keep it on the lightweight side. However, this package wouldn’t work at all without the {polyclip} dependency, which is the only one outside {ggplot2}’s imports.

Related work

Of course, the {grid} package, on which {ggplot2} is build upon, offers some options for arrows. The {arrowheadr} package provides some great extensions for arrowheads. The {vwlines} package that handles variable widths lines much more graciously than this package. Both the {gggenes} and {gggenomes} packages use arrows in a domain-specific context. For vector field visualisation, there is the {ggquiver} package. The {ggarchery} package also provides extended options for the geom_segment() parametrisation of lines.

ggarrow's People

Contributors

teunbrand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ggarrow's Issues

Feature request: support for linetype aesthetic

Not sure if this package is under active development, but I've found it really useful so figured I would try opening an issue.

I've been using geom_arrow_segment() in a project and one limitation I've faced is not being able to set a linetype aesthetic. As a workaround, I've been plotting a geom_segment() with the desired linetype in one layer and geom_arrow_segment() with a significantly shortened length in a second layer. This works reasonably well, but it would be great if geom_arrow_segment() could have native support for the linetype aesthetic.

I completely understand if this package isn't a priority (especially given all your recent work on ggplot2), so feel free to disregard if that's the case. Thank you for all the work you've put into this package already, it's been a great help to me.

Let the package be installed through `CRAN`

Hi, @teunbrand , Thanks for your excellent R pkg ❤️ !
Have you considered publishing ggarrow to CRAN? In China, it is very troublesome to install the R package from github because of the network. I want to use ggarrow as a dependency for my R package. It will be troublesome to install it from github.

Release ggarrow 0.1.0

First release:

Prepare for release:

  • git pull
  • usethis::use_github_links()
  • urlchecker::url_check()
  • devtools::build_readme()
  • devtools::check(remote = TRUE, manual = TRUE)
  • devtools::check_win_devel()
  • git push
  • Draft blog post

Submit to CRAN:

  • usethis::use_version('minor')
  • devtools::submit_cran()
  • Approve email

Wait for CRAN...

  • Accepted 🎉
  • Add preemptive link to blog post in pkgdown news menu
  • usethis::use_github_release()
  • usethis::use_dev_version(push = TRUE)
  • Finish blog post
  • Tweet

Feature request: implement wavy line drawing capability

Currently, ggarrow offers the ability to draw straight and curvy lines. It would be incredibly useful to extend the package functionality to include the ability to create wavy lines.
I believe this feature would add significant value to ggarrow and make it an even more powerful tool for a variety of users.
Let me know if you'd like help refining this issue or adding more specific details!

Visual bug: corners

When points are spaced more densely than the linewidth, a glitch can occur at corners where a sharp angle transitions into a smooth curve.

library(ggarrow)
#> Loading required package: ggplot2
t <- seq(0, 2 * pi, length.out = 1000)

df <- data.frame(
  x = c(0.25, sin(t) + seq(0, 2, length.out = 1000), 1.75),
  y = c(2, cos(t), 2)
)

ggplot(df, aes(x, y)) +
  geom_arrow(linewidth = 5, colour = "white", stroke_colour = "black") +
  annotate("point", x = 0, y = 1, colour = 2, shape = 1, size = 20) +
  coord_equal()

Created on 2023-01-31 with reprex v2.0.2

Related question on SO: https://stackoverflow.com/questions/74331763/offsetting-a-polyline-in-one-direction-part-ii

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.