40

Possible Duplicate:
Equation-driven smoothly shaded concentric shapes

How could I plot a symmetrical heart in R like I plot a circle (using plotrix) or a rectangle?

I'd like code for this so that I could actually do it for my self and to be able to generalize this to similar future needs. I've seen even more elaborate plots than this so it's pretty doable, it's just that I lack the knowledge to do it.

Community
  • 1
  • 1
Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
  • 33
    Valetines day is still 3 months off, cupid must have hit you pretty hard. – Johan Nov 10 '11 at 16:04
  • 6
    Not sure about implementation in `r`, but you'll likely be interested in [cardiod polar equation](http://mathworld.wolfram.com/Cardioid.html), and / or [other routes](http://mathworld.wolfram.com/HeartCurve.html). – Grant Thomas Nov 10 '11 at 16:05
  • I used the last eqn in the Wolfram page in the above link as the source of the parametric eqn and just calculated over 0 -> 2pi. – IRTFM Nov 10 '11 at 16:24
  • 4
    For a shaded version, see this: http://stackoverflow.com/q/6542825/269476 – James Nov 10 '11 at 16:31
  • it's not really an exact duplicate, is it? there are just some overlapping answers ... – Ben Bolker Nov 10 '11 at 17:22
  • I'm voting to close, but it should remain un-deleted for it's excellent answers and more Google-able title. – joran Nov 11 '11 at 00:16

8 Answers8

89

This is an example of plotting a "parametric equation", i.e. a pairing of two separate equations for x and y that share a common parameter. You can find many common curves and shapes that can be written within such a framework.

dat<- data.frame(t=seq(0, 2*pi, by=0.1) )
 xhrt <- function(t) 16*sin(t)^3
 yhrt <- function(t) 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t)
 dat$y=yhrt(dat$t)
 dat$x=xhrt(dat$t)
 with(dat, plot(x,y, type="l"))

Other Parametric (and implicit and polar) Heart Eqns

You also could "heat it up" with using the "fill" capability of the polygon function:

with(dat, polygon(x,y, col="hotpink"))   

And if you just want little hearts to sprinkle around at various places, you could use the Symbol font version of "heart" after looking at the help(points) page and using the TestChars function:

points(c(10,-10, -15, 15), c(-10, -10, 10, 10), pch=169, font=5)

enter image description here

Windows users may want to see if adding the Cairo package helps gain access to card symbols including "hearts".( When I tested the TestChars function on the WinXP "side" of my MacPro I did not get hearts, and paging through the "special symbols" in MS-Word did not uncover anything. So I did a search of Rhelp and found a recent posting by Ivo Welch. He was reporting a bug, but they look OK on my machine.) Further note... I think the hearts and diamonds codes in his were reversed.

library(Cairo)

clubs <- expression(symbol('\247'))
hearts <- expression(symbol('\251'))
diamonds <- expression(symbol('\250'))
spades <- expression(symbol('\252'))
csymbols <- c(clubs, hearts, diamonds, spades)

plot( 0, xlim=c(0,5), ylim=c(0,2), type="n" )
clr <- c("black", "red", "red", "black") 
for (i in 1:4) {
  hline <- function( yloc, ... ) 
         for (i in 1:length(yloc)) 
             lines( c(-1,6), c(yloc[i],yloc[i]), col="gray")  
              hline(0.9); 
                hline(1.0);
                hline(1.1);
                hline(1.2)  
 text( i, 1, csymbols[i], col=clr[i], cex=5 )  
 text( i, 0.5, csymbols[i], col=clr[i] ) }

# Also try this
plot(1,1)
text(x=1+0.2*cos(seq(0, 2*pi, by=.5)), 
     y=1+0.2*sin(seq(0, 2*pi, by=.5)), 
                  expression(symbol('\251') ) )

enter image description here

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • I actually want the little symbols but pch 169 on my machine is the copyright symbol "©". What would I need to do to make a heart symbol with `points(x,y, pch)`? I'm think font family or somthing like that but am unsure of how to approach this. – Tyler Rinker Nov 10 '11 at 17:54
  • The links in my comment (#2) on @aL3xa's answer might be useful ... – Ben Bolker Nov 10 '11 at 18:04
  • @Tyler Rinker: Define and run the function `TestChars(font=5)` at the end of the examples on the help(points) page. It will print out all the Symbol glyphs for your system that are indexed by the decimal numbers: `c(32:126, 160:254)` – IRTFM Nov 10 '11 at 22:16
  • (+1) for "heating it up" – Rich Scriven May 01 '14 at 23:55
  • Very beautiful shape! – Travis Feb 14 '20 at 12:29
20

From a blog post:

Solve the parametric equation for y (does SO allow math formatting?)

x^2 + (5y/4-sqrt(abs(x)))^2 = 1

sqrt(1-x^2) = 5y/4 - sqrt(abs(x))

y = 4/5*(sqrt(1-x^2)+sqrt(abs(x)))

MASS::eqscplot(0:1,0:1,type="n",xlim=c(-1,1),ylim=c(-0.8,1.5))
curve(4/5*sqrt(1-x^2)+sqrt(abs(x)),from=-1,to=1,add=TRUE,col=2)
curve(4/5*-sqrt(1-x^2)+sqrt(abs(x)),from=-1,to=1,add=TRUE,col=2)

enter image description here

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • fair enough. Do you know an *easy* way to generate MathML? (I get spoiled by CrossValidated, which automatically renders LaTeX ... – Ben Bolker Feb 14 '20 at 21:19
  • https://tex.stackexchange.com/questions/227195/latex-to-mathml-conversion-tools-limitations-and-approaches – Ben Bolker Feb 14 '20 at 21:43
  • 1
    Looks like I was wrong. Here's MetaSO discussion of why MathJax won't be turned on: https://meta.stackoverflow.com/questions/252282/theres-seriously-no-reason-why-latex-markup-via-mathjax-shouldnt-be-enabled-on?r=SearchResults&s=1|0.0000 Appears that the extra half-second to load is not considered worthwhile for those of us using higher level languages where it makes sense. The C-users are calling the shots. – IRTFM Feb 14 '20 at 22:00
  • It might (?) be possible to embed MathJax manually? https://stackoverflow.com/questions/5865522/which-browsers-do-support-mathml – Ben Bolker Feb 14 '20 at 22:50
19

Simple and ugly hack:

plot(1, 1, pch = "♥", cex = 20, xlab = "", ylab = "", col = "firebrick3")
aL3xa
  • 35,415
  • 18
  • 79
  • 112
  • 1
    DISCLAIMER: I'm perfectly aware of the fact that this is not what you want, and I'd really like to see the actual code you were looking for. =) – aL3xa Nov 10 '11 at 16:16
  • 2
    But this could actually be a very nice starting point if one wanted to use hearts as plotting characters: see http://stackoverflow.com/questions/5886018/using-unicode-dingbat-like-glyphs-in-r-graphics-across-devices-platforms-e and http://www.fileformat.info/info/unicode/char/search.htm?q=heart&preview=entity – Ben Bolker Nov 10 '11 at 16:42
  • 5
    But if walks like a heart and quacks like a heart, it must be a heart. :) – Roman Luštrik Nov 10 '11 at 16:47
  • @ aL3xa Yours is the one that actually looks the most promising for my crude needs (lots of great posts here). Problem is `pch = "♥"` doesn't work for me. R converts it to a "?". I'm a windows 7 user so this may be the reason. I can use all sorts of crazy numeric values for pch but have yet to find the heart you used. Also any pointers/resources on how to determine what number coresponds to what symbol with pch would be awesome. Generally the resources I've seen have only a few symbols corresponding to numbers. I know there's 100s of them though. – Tyler Rinker Nov 10 '11 at 17:24
  • @Tyler Rinker: I added a pch solution from the help(points) page. Should work if you have a Symbol font in your pdf-fonts library. – IRTFM Nov 10 '11 at 17:49
  • 1
    Using unicode values for pch works. I've learned alot about symbols and just opened up a whole new bag of tricks using Unicode. `plot(1, 1, pch = -0x2665L, cex = 20, xlab = "", ylab = "", col = "firebrick3")` – Tyler Rinker Nov 10 '11 at 18:10
  • As an added note the male and female symbols (thought this was only available to S users) are available through Unicode as well using: `points(1,1, pch=-0x2642L, cex = 20, col = "firebrick3") ` & `points(1,1, pch=-0x2642L, cex = 20, col = "firebrick3") ` These could be useful. – Tyler Rinker Nov 10 '11 at 18:13
  • See Unicode stuff here: http://www.fileformat.info/info/unicode/char/2665/index.htm And frankly, I think that @DWin deserved the checkmark. My answer doesn't include a single line of maths. =/ – aL3xa Nov 10 '11 at 18:20
  • @aL3xa Yeah this one was hard to assign credit to because they all were terrific answers. The one that best met my needs was a simplier version of plotting symbols. I didn't realize that until you posed it. Per your request I assigned DWin the check. – Tyler Rinker Nov 10 '11 at 19:51
  • @TylerRinker that's the spirit! Besides, he posted a larger heart! =) – aL3xa Nov 10 '11 at 20:08
  • 1
    I think I may have come up with a Windows-specific approach. It won't be a pch argument but you can use `text(x,y, heart, col="red")` in stead of `points(x,y,pch)`. – IRTFM Nov 10 '11 at 23:14
12

Here is a cardioid in ggplot:

library(ggplot2)

dat <- data.frame(x=seq(0, 2*pi, length.out=100))
cardioid <- function(x, a=1)a*(1-cos(x))
ggplot(dat, aes(x=x)) + stat_function(fun=cardioid) + coord_polar()

enter image description here

And the heart plot (linked by @BenBolker):

heart <- function(x)2-2*sin(x) + sin(x)*(sqrt(abs(cos(x))))/(sin(x)+1.4)
ggplot(dat, aes(x=x)) + stat_function(fun=heart) + coord_polar(start=-pi/2)

enter image description here

Andrie
  • 176,377
  • 47
  • 447
  • 496
10

Another option,

xmin <- -5
xmax <- 10
n <- 1e3
xs<-seq(xmin,xmax,length=n)
ys<-seq(xmin,xmax,length=n)

f = function(x, y) (x^2+0.7*y^2-1)^3 - x^2*y^3
zs <- outer(xs,ys,FUN=f)

h <- contourLines(xs,ys,zs,levels=0)
library(txtplot)
with(h[[1]], txtplot(x, y))



     +---+-******----+----******-+---+
 1.5 + *****    **********     ***** +
   1 +**                           * +
 0.5 +**                           * +
     | ***                       *** |
   0 +   ****                 ****   +
-0.5 +      *****         *****      +
  -1 +          ***********          +
     +---+-----+-----*-----+-----+---+
        -1   -0.5    0    0.5    1    
Ricardo Oliveros-Ramos
  • 4,322
  • 2
  • 25
  • 42
baptiste
  • 75,767
  • 19
  • 198
  • 294
6

If you want to be more "mature", try out the following (posted to R-help a few years ago):

thong<-function(h = 9){ 
     # set up plot  
    xrange=c(-15,15)  
    yrange=c(0,16)  
    plot(0,xlim=xrange,ylim=yrange,type='n')  

     # draw outer envelope  
    yr=seq(yrange[1],yrange[2],len=50)  
    offsetFn=function(y){2*sin(0+y/3)}  
    offset=offsetFn(yr)  
    leftE = function(y){-10-offsetFn(y)}  
    rightE = function(y){10+offsetFn(y)}  

    xp=c(leftE(yr),rev(rightE(yr))) 
    yp=c(yr,rev(yr))  
    polygon(xp,yp,col="#ffeecc",border=NA) 

    # feasible region upper limit: 
    # left and right defined by triple-log function:  
    xt=seq(0,rightE(h),len=100)   
    yt=log(1+log(1+log(xt+1)))   
    yt=yt-min(yt)  
    yt=h*yt/max(yt)  
    x=c(leftE(h),rightE(h),rev(xt),-xt) 
    y=c(h,h,rev(yt),yt) 
    polygon(x,y,col="red",border=NA)  
}
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
Carl Witthoft
  • 20,573
  • 9
  • 43
  • 73
3

A few more varieties:

equations

Mihai Rotaru
  • 1,953
  • 3
  • 26
  • 28
  • 3
    I didn't downvote this, but I think it was downvoted because it's nothing more than a link to a set of parametric equations that are linked (directly or indirectly) by several of the other answers here. – Ben Bolker Nov 10 '11 at 23:32
2

I do not know anything about R, but if you plot this function you will get a heart:

x^2+(y-(x^2)^(1/3))^2=1
dimme
  • 4,393
  • 4
  • 31
  • 51