How can I randomly select 1000 points uniformly from the shaded area below the plotted curve?
Plot[1/π Cos[θ]^2, {θ, 0, 2 π}, Filling -> Bottom]
How can I randomly select 1000 points uniformly from the shaded area below the plotted curve?
Plot[1/π Cos[θ]^2, {θ, 0, 2 π}, Filling -> Bottom]
As noted in my comment, one approach is as follows. First, generate thousands of pairs of random numbers in the range {0, 2 π}
, {0, 1/π}
. Then select the first 1000 that lie below the curve.
lst = Transpose@{RandomReal[{0, 2 π}, 4000], RandomReal[{0, 1/π}, 4000]};
listsel = Select[lst, #[[2]] < 1/π Cos[#[[1]]]^2 &, 1000];
Show[Plot[1/π Cos[θ]^2, {θ, 0, 2 π}, Filling -> Bottom], ListPlot[listsel]]
This simple process works well provided the portion of points selected is a reasonable fraction of the total number of points, as it is here.
There is no need in filtering out random points in a rectangle that don't fall in the prescribed region. The sampling within a region can be done directly with RandomPoint
.
Specify the region:
reg = ImplicitRegion[0 <= x <= 2 Pi && 0 <= y <= 1/Pi Cos[x]^2, {x, y}]
and then one can sample a point with
RandomPoint[reg]
e.g., {0.39486, 0.0422331}
or several points n
with RandomPoint[reg, n]
. There's a warning about an unbounded region, so to keep it clean one can add bounds as a third argument to RegionPlot
:
data = RandomPoint[reg, 1000, {{0, 2 Pi}, {0, 1/Pi}}];
Show[RegionPlot[reg], ListPlot[data, Frame -> True], AspectRatio -> 1/GoldenRatio]
EDIT as per Trilarion's comment:
How does RandomPoint
work internally is beyond my knowledge, but the timing analysis shows that it does not sample a rectangle and throw away the points that don't fall in the region (and even if it does, it's a way faster implementation):
reg = ImplicitRegion[0 <= x <= 10 && y >= x && y <= x + 1, {x, y}]
n = 110000;
(lst = Transpose@{RandomReal[{0, 10}, n], RandomReal[{0, 11}, n]};
sel = Select[lst, #[[1]] <= #[[2]] <= #[[1]] + 1 &,
UpTo[10000]];) // AbsoluteTiming
Length@sel
{0.221189, Null}
9916
10000 points weren't even generated.
RandomPoint
approach:
pts = RandomPoint[reg, 10000, {{0, 10}, {0, 11}}]; // AbsoluteTiming
{0.049927, Null}
More than 4x faster, and all 10000 desired points are obviously generated.
More of a first principles approach, use the function as a PDF
to generate random x
data, then for each x
choose a uniformly distributed point on the vertical line {x, f[x]}
:
f[x_] := 1/π Cos[x]^2
z = Integrate[f[x], {x, 0, 2 π}]; (*can use NIntegrate here if needed*)
Plot[f[x], {x, 0, 2 π},
Epilog ->
Point[
{#, First@RandomVariate[UniformDistribution[{0, f[#]}], 1]} & /@
RandomVariate[ProbabilityDistribution[f[x]/z, {x, 0, 2 π}], 1000]
]
]
This is likely the fastest approach.
I think newer versions of ProbabilityDistribution
may do that normalization (/z
) automatically, btw.
In case where only the plot is given:
plot = Plot[1/π Cos[θ]^2, {θ, 0, 2 π}, Filling -> Bottom]
polygons = Cases[plot // Normal, _Polygon, ∞]
region = RegionUnion @@ polygons;
pts = RandomPoint[region, 100]; (*quite slow*)
Show[plot, Graphics@Point@pts]
Normal
. Perhaps Normal
is the answer the question regarding an alternative for FullGraphics ( mathematica.stackexchange.com/questions/83648/…).
$\endgroup$
GraphicsComplex
to regular primitives.
$\endgroup$