The Buffon needle problem says that if we drop a needle of length d on a floor with lines parallel that are l inches apart, then the probability, p, that the needle crosses a line is
If the needle is d = 1/2 inches long and the lines are l = 1 inch apart, then
In other words, we have a way to estimate π by way of a simulation. The animation below does just that. On the left side are the needles being “dropped,” and on the right is the associated inverse probability that a needle crosses the line. This is done 100 times. The convergence is on the slow side, so the estimation with 100 trials (a carefully chosen 100 trials) has an estimate of 3.225806. The R code is below.
If you enjoy this fun probability fact and animation, please share, subscribe, and like.
Please share and like
Please help me find readers by forwarding this article to your friends (and even those who aren't your friends), sharing this post on social media, and clicking like. If you're on Twitter, you can find me at BriefedByData. If you have any article ideas, feedback, or other views, please email me at briefedbydata@substack.com.
Thank you
In a crowded media market, it's hard to get people to read your work. I have a long way to go, and I want to say thank you to everyone who has helped me find and attract subscribers.
Disagreeing and using comments
I'd rather know the truth and understand the world than always be right. I'm not writing to upset or antagonize anyone on purpose, though I guess that could happen. I welcome dissent and disagreement in the comments. We all should be forced to articulate our viewpoints and change our minds when we need to, but we should also know that we can respectfully disagree and move on. So, if you think something said is wrong or misrepresented, then please share your viewpoint in the comments.
R Code
## Packages
library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)
library(animation)
library(patchwork)
## Colors
MyBlue <- "#437fca"
MyRed <- "#be4242"
MyPurple <- "#5B005B"
MyLightP <- "#dfdbdf"
MyLightP2 <- "#f8f4f8"
MyLightP3 <- "#fcfafc"
## Defined Variables
CaptionData <- ""
## Create Data
Pins <- 100
Buffon <- data.frame("Drop" = 1:Pins,
"xPoint" = runif(Pins, min = 0, max = 1),
"yPoint" = runif(Pins, min = 0, max = 1),
"theta" = runif(Pins, 0, pi)
)
Buffon <- Buffon %>%
mutate( xStart = ifelse(theta < pi / 2, xPoint - cos(theta) / 4,
xPoint - cos(pi - theta) / 4),
yStart = ifelse(theta < pi/2, yPoint - sin(theta) / 4,
yPoint + sin(pi - theta) / 4),
xEnd = ifelse(theta < pi/2, xPoint + cos(theta) / 4,
xPoint + cos(pi - theta) / 4),
yEnd = ifelse(theta < pi/2, yPoint + sin(theta) / 4,
yPoint - sin(pi - theta) / 4),
Cross = ifelse(yStart >= 1 | yStart <= 0 | yEnd >= 1 | yEnd <= 0, 1, 0),
CrossCount = cumsum(Cross),
InProb = Drop/CrossCount
)
# Set Graph Frame
dev.new(width = 1400,height = 700,unit = "px")
## Create Annimation
saveGIF(
{
ani.options(interval = 0.20, nmax = 50)
for(i in 2:Pins){
# Pin Drop Plot
p1 <- ggplot(Buffon[1:i,], aes(xPoint, yPoint)) +
geom_point(shape = 16, size = 3, color = MyBlue) +
geom_hline(yintercept = c(0, 1), color = MyRed, linewidth = 1.5) +
geom_segment(aes(x = xStart, y = yStart, xend = xEnd, yend = yEnd),
linewidth = 1.25)+
scale_x_continuous(limits = c(-0.25, 1.25), expand = c(0.01, 0.01)) +
scale_y_continuous(limits = c(-0.25, 1.25), expand = c(0.01, 0.01)) +
coord_fixed()+
theme(axis.text = element_text(size = 14),
axis.title = element_text(size = 16),
plot.title = element_text(size = 20),
plot.background = element_rect(fill = MyLightP3),
panel.background = element_rect(fill = MyLightP),
legend.background = element_rect(fill = MyLightP2),
plot.caption = element_text(hjust = c(1, 0), size = c(14, 14),
color = c(MyPurple, "black"))) +
labs(title="1/2 in Needles Dropped on 1 in Lines",
y = NULL, x = NULL,
caption = c("Briefed by Data || Thomas J Pfaff", CaptionData))
# Inverse Probability Plot
p2 <- ggplot(Buffon[1:i,], aes(x = Drop, y = InProb)) +
geom_point() + geom_line()+
geom_hline(yintercept = pi, color = MyPurple, linewidth = 1.5) +
xlim(1, Pins) +
scale_y_continuous(labels = function(x){format(x, nsmall = 1)}) +
theme(axis.text = element_text(size = 14),
axis.title = element_text(size = 16),
plot.title = element_text(size = 20),
plot.background = element_rect(fill = MyLightP3),
panel.background = element_rect(fill = MyLightP),
legend.background = element_rect(fill = MyLightP2),
plot.caption = element_text(hjust = c(1, 0), size = c(14, 14),
color = c(MyPurple, "black") ) )+
labs(title = "Inverse Probability the Needles Cross",
y = "Inverse Probability", x = NULL,
caption = c("Briefed by Data || Thomas J Pfaff", CaptionData))
print(p1 + p2 +
plot_annotation(title = "The Buffon Needle Problem",
theme = theme(plot.title = element_text(size = 24))
))
ani.pause()
}
for (k in 1:5){
print(p1 + p2 +
plot_annotation(title = "The Buffon Needle Problem",
theme = theme(plot.title = element_text(size = 30))
))
ani.pause()
}
}, movie.name = "Buffon.gif", ani.width = 1456, ani.height = 936)