Getting to the point – an alternative to the bezier arrow

An alternative bezier arrow to the regular grid-bezier. Apart from a cool gradient it has the advantages of: exact width, exact start/end points and axis alignment.
An alternative bezier arrow to the regular grid-bezier. Apart from a cool gradient it has the advantages of: exact width, exact start/end points and axis alignment.

About two weeks ago I got frustrated with the bezierGrob function in the grid package. The lwd parameter is interpreted differently depending on device, the arrow at the end does not follow the line but is perpendicular (probably following the spline control), and the line parameter makes it difficult to control exactly where the line starts/ends. Thus I decided to make my own fancy line with an arrow at the end – at the time I thought: How hard can it be? In retrospect, I wish I never thought of the thing… This article is about the painful process of creating of an alternative to the bezierGrob.

The end result

Based upon this article I have created two functions for generating these arrows, you can find them in my Gmisc-package, the bezierArrowSmpl and bezierArrowSmplGradient functions. Both functions should be fully documented, although the second one with the gradient is still somewhat of a beta as there are more features that I’m thinking of adding in the future. The first basic arrow is actually just a polygonGrob while the gradient arrow builds upon this one with a gradient layer on top – all merged into a gList grob. Grob stands for graphical object as defined by the grid-package. One day I also hope to convert these into proper grobs according to Paul Murrel’s grob-concept, but after skimming through the manual I quickly decided that it will have to wait for a while… right now I’m just happy that it works after a lot of debugging.

The process

So I started out with just generating some settings so that it would be easier to convert into a function later on.

So by calling the bezierGrob function we get a nice curvy line.

First_line

Next we get the actual points of the bezier curve. We also want the viewport’s values so we need to convert it all the values into npc. On top of this I prefer to remove the unit as this complicates the calculations.

Lets see if we can plot a polygon using the points. As you can see the width isn’t really as expected since the shift is only vertical.

Line_with_vertical_shift_2

Cutting the curve at the arrow

We want to cut the bezier curve so that we get an arrow of a certain length. This turned out to be a little tricky as I needed to find the point that is the closes corresponding one to my desired length.

Now lets see where that gets us.

Clipped_line_cmp_org_3

It seems rather obvious that we can’t use the same spline controls. The best solution is to adjust the spline control so that it matches the direction of the arrow. It’s not perfect but since I’m not familiar with the bezier generating code (the xspline function), it will have to do.

Adjusted_line_cmp_org_4

The rectangle

Now let’s kick of with the rectangle that we want. In this step we need to offset the lines by a certain amount. All those hours with linear algebra actually simplified it a little.

Polygon_simple_shift_52

Although this may look a little artistic, it causes some issues, the line width should be perpendicular to each node. To get this we need to recalculate each node. Although theoretically it is time consuming, graphs shouldn’t be that sensitive to slow performance. There is probably a matrix short-cut, but then it would loose the width unit as the operations on a unit are limited. I also found it better to actually average the angle between the nodes.

Polygon_with_rotation_6

Now lets see if we can get the left side to be vertical.

Polygon_with_rotation_left_vert_72

It looks OK with the vertical althought there as the angle increases to 45 degrees I should probably change the bezier adding code. Now lets finally add the arrow.

Polygon_with_arrow_82

The damn gradient

Now to the really tricky part, adding a color gradient. I did have a lot of fun in this section although in the end the debugging was really tiresome. This section is more expanded in the bezierArrowSmplGradient function.

Gradient_arrow2

Phew… that’s it. In the actual code I’ve changed the top/bottom to left/right indicating the direction of the arrow. I’ve also added some other stuff to make it more general. If you have some suggestions for improvements or want to help out with creating proper grobs out of the functions it would be appreciated.

Flattr this!

This entry was posted in R and tagged , , . Bookmark the permalink.

3 Responses to Getting to the point – an alternative to the bezier arrow

  1. Marcus says:

    Good lord, this is insane. I get a headache just looking at the code. Nice work though.

    • Max Gordon says:

      Yep, pure insanity. Including docs and all the extra functions I ended up with about 1000 lines of code. Although I hope someone besides me has some use of it.

  2. Dieter Menne says:

    Great stuff, and pure insanity. It’s totally useless, but creates great effects in transition plots. The medical colleagues who use it for stuff like your’s found it “better than PowerPoint”, which I considered an insult.

    Thanks a lot for all your wasted debug hours!

    Dieter

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.