Improving the speed of creation for three Perlin Noise Maps in Python?
$begingroup$
I am interested in learning how I can improve the speed of the code in this pygame file. I iterate over 6400 * 1800 * 3 or 34,560,000 elements of various numpy arrays here to apply noise values to them. The noise library I'm using can be found on GitHub here.
I am calling static variables from a class called ST
here. ST.MAP_WIDTH
= 6400 and ST.MAP_HEIGHT
= 1800. All other ST
attributes called here are assigned in the code. They are the noise-maps I'm making.
from __future__ import division
from singleton import ST
import numpy as np
import noise
import timeit
import random
import math
def __noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
random.randint(1, 9999))
return np.float32(value)
def __elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 8, 0.9)
def __climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = math.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = __noise(noise_x, noise_y, 8, 0.7)
return (1 + value - distance) / 2
def __rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
start = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
randomizer = random.uniform(0.0001, 0.9999)
# assign noise map values
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y][x] = __elevation_mapper(noise_x, noise_y)
climate_arr[y][x] = __climate_mapper(y, noise_x, noise_y)
rainfall_arr[y][x] = __rainfall_mapper(noise_x, noise_y)
# normalize to range [0, 1] and assign to relevant ST attributes
ST.ELEVATIONS = (elevation_arr - elevation_arr.min()) /
(elevation_arr.max() - elevation_arr.min())
ST.CLIMATES = (climate_arr - climate_arr.min()) /
(climate_arr.max() - climate_arr.min())
ST.RAINFALLS = (rainfall_arr - rainfall_arr.min()) /
(rainfall_arr.max() - rainfall_arr.min())
stop = timeit.default_timer()
print("GENERATION TIME: " + str(stop - start))
python performance python-2.x numpy
$endgroup$
add a comment |
$begingroup$
I am interested in learning how I can improve the speed of the code in this pygame file. I iterate over 6400 * 1800 * 3 or 34,560,000 elements of various numpy arrays here to apply noise values to them. The noise library I'm using can be found on GitHub here.
I am calling static variables from a class called ST
here. ST.MAP_WIDTH
= 6400 and ST.MAP_HEIGHT
= 1800. All other ST
attributes called here are assigned in the code. They are the noise-maps I'm making.
from __future__ import division
from singleton import ST
import numpy as np
import noise
import timeit
import random
import math
def __noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
random.randint(1, 9999))
return np.float32(value)
def __elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 8, 0.9)
def __climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = math.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = __noise(noise_x, noise_y, 8, 0.7)
return (1 + value - distance) / 2
def __rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
start = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
randomizer = random.uniform(0.0001, 0.9999)
# assign noise map values
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y][x] = __elevation_mapper(noise_x, noise_y)
climate_arr[y][x] = __climate_mapper(y, noise_x, noise_y)
rainfall_arr[y][x] = __rainfall_mapper(noise_x, noise_y)
# normalize to range [0, 1] and assign to relevant ST attributes
ST.ELEVATIONS = (elevation_arr - elevation_arr.min()) /
(elevation_arr.max() - elevation_arr.min())
ST.CLIMATES = (climate_arr - climate_arr.min()) /
(climate_arr.max() - climate_arr.min())
ST.RAINFALLS = (rainfall_arr - rainfall_arr.min()) /
(rainfall_arr.max() - rainfall_arr.min())
stop = timeit.default_timer()
print("GENERATION TIME: " + str(stop - start))
python performance python-2.x numpy
$endgroup$
1
$begingroup$
Have a look atnumpy.meshgrid
and its examples. I think they'll do what you need.
$endgroup$
– Austin Hastings
6 hours ago
add a comment |
$begingroup$
I am interested in learning how I can improve the speed of the code in this pygame file. I iterate over 6400 * 1800 * 3 or 34,560,000 elements of various numpy arrays here to apply noise values to them. The noise library I'm using can be found on GitHub here.
I am calling static variables from a class called ST
here. ST.MAP_WIDTH
= 6400 and ST.MAP_HEIGHT
= 1800. All other ST
attributes called here are assigned in the code. They are the noise-maps I'm making.
from __future__ import division
from singleton import ST
import numpy as np
import noise
import timeit
import random
import math
def __noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
random.randint(1, 9999))
return np.float32(value)
def __elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 8, 0.9)
def __climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = math.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = __noise(noise_x, noise_y, 8, 0.7)
return (1 + value - distance) / 2
def __rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
start = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
randomizer = random.uniform(0.0001, 0.9999)
# assign noise map values
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y][x] = __elevation_mapper(noise_x, noise_y)
climate_arr[y][x] = __climate_mapper(y, noise_x, noise_y)
rainfall_arr[y][x] = __rainfall_mapper(noise_x, noise_y)
# normalize to range [0, 1] and assign to relevant ST attributes
ST.ELEVATIONS = (elevation_arr - elevation_arr.min()) /
(elevation_arr.max() - elevation_arr.min())
ST.CLIMATES = (climate_arr - climate_arr.min()) /
(climate_arr.max() - climate_arr.min())
ST.RAINFALLS = (rainfall_arr - rainfall_arr.min()) /
(rainfall_arr.max() - rainfall_arr.min())
stop = timeit.default_timer()
print("GENERATION TIME: " + str(stop - start))
python performance python-2.x numpy
$endgroup$
I am interested in learning how I can improve the speed of the code in this pygame file. I iterate over 6400 * 1800 * 3 or 34,560,000 elements of various numpy arrays here to apply noise values to them. The noise library I'm using can be found on GitHub here.
I am calling static variables from a class called ST
here. ST.MAP_WIDTH
= 6400 and ST.MAP_HEIGHT
= 1800. All other ST
attributes called here are assigned in the code. They are the noise-maps I'm making.
from __future__ import division
from singleton import ST
import numpy as np
import noise
import timeit
import random
import math
def __noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
random.randint(1, 9999))
return np.float32(value)
def __elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 8, 0.9)
def __climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = math.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = __noise(noise_x, noise_y, 8, 0.7)
return (1 + value - distance) / 2
def __rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return __noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
start = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
randomizer = random.uniform(0.0001, 0.9999)
# assign noise map values
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y][x] = __elevation_mapper(noise_x, noise_y)
climate_arr[y][x] = __climate_mapper(y, noise_x, noise_y)
rainfall_arr[y][x] = __rainfall_mapper(noise_x, noise_y)
# normalize to range [0, 1] and assign to relevant ST attributes
ST.ELEVATIONS = (elevation_arr - elevation_arr.min()) /
(elevation_arr.max() - elevation_arr.min())
ST.CLIMATES = (climate_arr - climate_arr.min()) /
(climate_arr.max() - climate_arr.min())
ST.RAINFALLS = (rainfall_arr - rainfall_arr.min()) /
(rainfall_arr.max() - rainfall_arr.min())
stop = timeit.default_timer()
print("GENERATION TIME: " + str(stop - start))
python performance python-2.x numpy
python performance python-2.x numpy
edited 7 hours ago
LuminousNutria
asked 9 hours ago
LuminousNutriaLuminousNutria
1805
1805
1
$begingroup$
Have a look atnumpy.meshgrid
and its examples. I think they'll do what you need.
$endgroup$
– Austin Hastings
6 hours ago
add a comment |
1
$begingroup$
Have a look atnumpy.meshgrid
and its examples. I think they'll do what you need.
$endgroup$
– Austin Hastings
6 hours ago
1
1
$begingroup$
Have a look at
numpy.meshgrid
and its examples. I think they'll do what you need.$endgroup$
– Austin Hastings
6 hours ago
$begingroup$
Have a look at
numpy.meshgrid
and its examples. I think they'll do what you need.$endgroup$
– Austin Hastings
6 hours ago
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Losing your Loops
Austin Hastings' comment gives you a good hint where to look at. The main takeaway for you should be:
(Most) loops are damn slow in Python. Especially multiple nested loops.
NumPy can help to vectorize your code, i.e. in this case that more of the looping is done in the C backend instead of in the Python interpreter. I would highly recommend to have a listen to the talk Losing your Loops: Fast Numerical Computing with NumPy by Jake VanderPlas. Although primarily tailored towards data science, it gives a good overview on the topic.
I did some slight modifications to your original script to include some of the vectorization ideas while still using your chosen Perlin noise library. (Sidenote: I changed the __
prefix to a single _
, because that is the convention most Python programmers use for internal functions. See PEP8 style guide.)
# -*- coding: utf-8 -*-
from __future__ import division, print_function
import numpy as np
import noise
import timeit
class ST(object):
MAP_HEIGHT = 1800
MAP_WIDTH = 6400
def _noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
if isinstance(noise_x, np.ndarray):
#rand_seed = np.random.randint(1, 9999, noise_x.size)
rand_seed = np.ones((noise_x.size, )) # just for comparison
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
return value.reshape(noise_x.shape)
else:
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
1.0) # just for comparison
#np.random.randint(1, 9999))
return np.float32(value)
def _elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 8, 0.9)
def _climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = np.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = _noise(noise_x, noise_y, 8, 0.7)
return (1.0 + value - distance) / 2.0
def _rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
# assign noise map values
randomizer = np.random.uniform(0.0001, 0.9999)
start_arr = timeit.default_timer()
X, Y = np.mgrid[0:ST.MAP_WIDTH, 0:ST.MAP_HEIGHT]
noise_x = X / ST.MAP_WIDTH - randomizer
noise_y = Y / ST.MAP_HEIGHT - randomizer
elevation_arr_np = _elevation_mapper(noise_x, noise_y)
climate_arr_np = _climate_mapper(Y, noise_x, noise_y)
rainfall_arr_np = _rainfall_mapper(noise_x, noise_y)
duration_arr = timeit.default_timer() - start_arr
start_loop = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y, x] = _elevation_mapper(noise_x, noise_y)
climate_arr[y, x] = _climate_mapper(y, noise_x, noise_y)
rainfall_arr[y, x] = _rainfall_mapper(noise_x, noise_y)
duration_loop = timeit.default_timer() - start_loop
print(np.allclose(elevation_arr, elevation_arr_np.T))
print(np.allclose(climate_arr, climate_arr_np.T))
print(np.allclose(rainfall_arr, rainfall_arr_np.T))
print("GENERATION TIME: loop: {:.6f}, array: {:.6f}".format(duration_loop, duration_arr))
if __name__ == "__main__":
create_map_arr()
The bottleneck is still in
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
and it would be highly favorable to use an implementation which supports 2D input, preferably from NumPy, directly (see further reading below).
Nevertheless, the modifications bring the execution time down to a third of the original time on my machine (which is not that powerful):
True
True
True
GENERATION TIME: loop: 338.094228, array: 101.549388
Those three True
s are from a little test I added to check if the generated maps are the same within reasonable accuracy. For this purpose the additional random value in _noise
was disabled.
Further reading
There have also already been similar questions on Code Review (see, e.g. here), where a reviewer created a Perlin noise implementation purely in Numpy. There also seems to be a GitHub project also doing Perlin noise with Numpy. So maybe have a look at them if your not forced to stick with noise
.
$endgroup$
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216186%2fimproving-the-speed-of-creation-for-three-perlin-noise-maps-in-python%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Losing your Loops
Austin Hastings' comment gives you a good hint where to look at. The main takeaway for you should be:
(Most) loops are damn slow in Python. Especially multiple nested loops.
NumPy can help to vectorize your code, i.e. in this case that more of the looping is done in the C backend instead of in the Python interpreter. I would highly recommend to have a listen to the talk Losing your Loops: Fast Numerical Computing with NumPy by Jake VanderPlas. Although primarily tailored towards data science, it gives a good overview on the topic.
I did some slight modifications to your original script to include some of the vectorization ideas while still using your chosen Perlin noise library. (Sidenote: I changed the __
prefix to a single _
, because that is the convention most Python programmers use for internal functions. See PEP8 style guide.)
# -*- coding: utf-8 -*-
from __future__ import division, print_function
import numpy as np
import noise
import timeit
class ST(object):
MAP_HEIGHT = 1800
MAP_WIDTH = 6400
def _noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
if isinstance(noise_x, np.ndarray):
#rand_seed = np.random.randint(1, 9999, noise_x.size)
rand_seed = np.ones((noise_x.size, )) # just for comparison
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
return value.reshape(noise_x.shape)
else:
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
1.0) # just for comparison
#np.random.randint(1, 9999))
return np.float32(value)
def _elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 8, 0.9)
def _climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = np.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = _noise(noise_x, noise_y, 8, 0.7)
return (1.0 + value - distance) / 2.0
def _rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
# assign noise map values
randomizer = np.random.uniform(0.0001, 0.9999)
start_arr = timeit.default_timer()
X, Y = np.mgrid[0:ST.MAP_WIDTH, 0:ST.MAP_HEIGHT]
noise_x = X / ST.MAP_WIDTH - randomizer
noise_y = Y / ST.MAP_HEIGHT - randomizer
elevation_arr_np = _elevation_mapper(noise_x, noise_y)
climate_arr_np = _climate_mapper(Y, noise_x, noise_y)
rainfall_arr_np = _rainfall_mapper(noise_x, noise_y)
duration_arr = timeit.default_timer() - start_arr
start_loop = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y, x] = _elevation_mapper(noise_x, noise_y)
climate_arr[y, x] = _climate_mapper(y, noise_x, noise_y)
rainfall_arr[y, x] = _rainfall_mapper(noise_x, noise_y)
duration_loop = timeit.default_timer() - start_loop
print(np.allclose(elevation_arr, elevation_arr_np.T))
print(np.allclose(climate_arr, climate_arr_np.T))
print(np.allclose(rainfall_arr, rainfall_arr_np.T))
print("GENERATION TIME: loop: {:.6f}, array: {:.6f}".format(duration_loop, duration_arr))
if __name__ == "__main__":
create_map_arr()
The bottleneck is still in
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
and it would be highly favorable to use an implementation which supports 2D input, preferably from NumPy, directly (see further reading below).
Nevertheless, the modifications bring the execution time down to a third of the original time on my machine (which is not that powerful):
True
True
True
GENERATION TIME: loop: 338.094228, array: 101.549388
Those three True
s are from a little test I added to check if the generated maps are the same within reasonable accuracy. For this purpose the additional random value in _noise
was disabled.
Further reading
There have also already been similar questions on Code Review (see, e.g. here), where a reviewer created a Perlin noise implementation purely in Numpy. There also seems to be a GitHub project also doing Perlin noise with Numpy. So maybe have a look at them if your not forced to stick with noise
.
$endgroup$
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
add a comment |
$begingroup$
Losing your Loops
Austin Hastings' comment gives you a good hint where to look at. The main takeaway for you should be:
(Most) loops are damn slow in Python. Especially multiple nested loops.
NumPy can help to vectorize your code, i.e. in this case that more of the looping is done in the C backend instead of in the Python interpreter. I would highly recommend to have a listen to the talk Losing your Loops: Fast Numerical Computing with NumPy by Jake VanderPlas. Although primarily tailored towards data science, it gives a good overview on the topic.
I did some slight modifications to your original script to include some of the vectorization ideas while still using your chosen Perlin noise library. (Sidenote: I changed the __
prefix to a single _
, because that is the convention most Python programmers use for internal functions. See PEP8 style guide.)
# -*- coding: utf-8 -*-
from __future__ import division, print_function
import numpy as np
import noise
import timeit
class ST(object):
MAP_HEIGHT = 1800
MAP_WIDTH = 6400
def _noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
if isinstance(noise_x, np.ndarray):
#rand_seed = np.random.randint(1, 9999, noise_x.size)
rand_seed = np.ones((noise_x.size, )) # just for comparison
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
return value.reshape(noise_x.shape)
else:
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
1.0) # just for comparison
#np.random.randint(1, 9999))
return np.float32(value)
def _elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 8, 0.9)
def _climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = np.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = _noise(noise_x, noise_y, 8, 0.7)
return (1.0 + value - distance) / 2.0
def _rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
# assign noise map values
randomizer = np.random.uniform(0.0001, 0.9999)
start_arr = timeit.default_timer()
X, Y = np.mgrid[0:ST.MAP_WIDTH, 0:ST.MAP_HEIGHT]
noise_x = X / ST.MAP_WIDTH - randomizer
noise_y = Y / ST.MAP_HEIGHT - randomizer
elevation_arr_np = _elevation_mapper(noise_x, noise_y)
climate_arr_np = _climate_mapper(Y, noise_x, noise_y)
rainfall_arr_np = _rainfall_mapper(noise_x, noise_y)
duration_arr = timeit.default_timer() - start_arr
start_loop = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y, x] = _elevation_mapper(noise_x, noise_y)
climate_arr[y, x] = _climate_mapper(y, noise_x, noise_y)
rainfall_arr[y, x] = _rainfall_mapper(noise_x, noise_y)
duration_loop = timeit.default_timer() - start_loop
print(np.allclose(elevation_arr, elevation_arr_np.T))
print(np.allclose(climate_arr, climate_arr_np.T))
print(np.allclose(rainfall_arr, rainfall_arr_np.T))
print("GENERATION TIME: loop: {:.6f}, array: {:.6f}".format(duration_loop, duration_arr))
if __name__ == "__main__":
create_map_arr()
The bottleneck is still in
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
and it would be highly favorable to use an implementation which supports 2D input, preferably from NumPy, directly (see further reading below).
Nevertheless, the modifications bring the execution time down to a third of the original time on my machine (which is not that powerful):
True
True
True
GENERATION TIME: loop: 338.094228, array: 101.549388
Those three True
s are from a little test I added to check if the generated maps are the same within reasonable accuracy. For this purpose the additional random value in _noise
was disabled.
Further reading
There have also already been similar questions on Code Review (see, e.g. here), where a reviewer created a Perlin noise implementation purely in Numpy. There also seems to be a GitHub project also doing Perlin noise with Numpy. So maybe have a look at them if your not forced to stick with noise
.
$endgroup$
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
add a comment |
$begingroup$
Losing your Loops
Austin Hastings' comment gives you a good hint where to look at. The main takeaway for you should be:
(Most) loops are damn slow in Python. Especially multiple nested loops.
NumPy can help to vectorize your code, i.e. in this case that more of the looping is done in the C backend instead of in the Python interpreter. I would highly recommend to have a listen to the talk Losing your Loops: Fast Numerical Computing with NumPy by Jake VanderPlas. Although primarily tailored towards data science, it gives a good overview on the topic.
I did some slight modifications to your original script to include some of the vectorization ideas while still using your chosen Perlin noise library. (Sidenote: I changed the __
prefix to a single _
, because that is the convention most Python programmers use for internal functions. See PEP8 style guide.)
# -*- coding: utf-8 -*-
from __future__ import division, print_function
import numpy as np
import noise
import timeit
class ST(object):
MAP_HEIGHT = 1800
MAP_WIDTH = 6400
def _noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
if isinstance(noise_x, np.ndarray):
#rand_seed = np.random.randint(1, 9999, noise_x.size)
rand_seed = np.ones((noise_x.size, )) # just for comparison
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
return value.reshape(noise_x.shape)
else:
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
1.0) # just for comparison
#np.random.randint(1, 9999))
return np.float32(value)
def _elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 8, 0.9)
def _climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = np.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = _noise(noise_x, noise_y, 8, 0.7)
return (1.0 + value - distance) / 2.0
def _rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
# assign noise map values
randomizer = np.random.uniform(0.0001, 0.9999)
start_arr = timeit.default_timer()
X, Y = np.mgrid[0:ST.MAP_WIDTH, 0:ST.MAP_HEIGHT]
noise_x = X / ST.MAP_WIDTH - randomizer
noise_y = Y / ST.MAP_HEIGHT - randomizer
elevation_arr_np = _elevation_mapper(noise_x, noise_y)
climate_arr_np = _climate_mapper(Y, noise_x, noise_y)
rainfall_arr_np = _rainfall_mapper(noise_x, noise_y)
duration_arr = timeit.default_timer() - start_arr
start_loop = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y, x] = _elevation_mapper(noise_x, noise_y)
climate_arr[y, x] = _climate_mapper(y, noise_x, noise_y)
rainfall_arr[y, x] = _rainfall_mapper(noise_x, noise_y)
duration_loop = timeit.default_timer() - start_loop
print(np.allclose(elevation_arr, elevation_arr_np.T))
print(np.allclose(climate_arr, climate_arr_np.T))
print(np.allclose(rainfall_arr, rainfall_arr_np.T))
print("GENERATION TIME: loop: {:.6f}, array: {:.6f}".format(duration_loop, duration_arr))
if __name__ == "__main__":
create_map_arr()
The bottleneck is still in
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
and it would be highly favorable to use an implementation which supports 2D input, preferably from NumPy, directly (see further reading below).
Nevertheless, the modifications bring the execution time down to a third of the original time on my machine (which is not that powerful):
True
True
True
GENERATION TIME: loop: 338.094228, array: 101.549388
Those three True
s are from a little test I added to check if the generated maps are the same within reasonable accuracy. For this purpose the additional random value in _noise
was disabled.
Further reading
There have also already been similar questions on Code Review (see, e.g. here), where a reviewer created a Perlin noise implementation purely in Numpy. There also seems to be a GitHub project also doing Perlin noise with Numpy. So maybe have a look at them if your not forced to stick with noise
.
$endgroup$
Losing your Loops
Austin Hastings' comment gives you a good hint where to look at. The main takeaway for you should be:
(Most) loops are damn slow in Python. Especially multiple nested loops.
NumPy can help to vectorize your code, i.e. in this case that more of the looping is done in the C backend instead of in the Python interpreter. I would highly recommend to have a listen to the talk Losing your Loops: Fast Numerical Computing with NumPy by Jake VanderPlas. Although primarily tailored towards data science, it gives a good overview on the topic.
I did some slight modifications to your original script to include some of the vectorization ideas while still using your chosen Perlin noise library. (Sidenote: I changed the __
prefix to a single _
, because that is the convention most Python programmers use for internal functions. See PEP8 style guide.)
# -*- coding: utf-8 -*-
from __future__ import division, print_function
import numpy as np
import noise
import timeit
class ST(object):
MAP_HEIGHT = 1800
MAP_WIDTH = 6400
def _noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2.0):
"""
Generates and returns a noise value.
:param noise_x: The noise value of x
:param noise_y: The noise value of y
:return: numpy.float32
"""
if isinstance(noise_x, np.ndarray):
#rand_seed = np.random.randint(1, 9999, noise_x.size)
rand_seed = np.ones((noise_x.size, )) # just for comparison
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
return value.reshape(noise_x.shape)
else:
value = noise.pnoise2(noise_x, noise_y,
octaves, persistence, lacunarity,
1.0) # just for comparison
#np.random.randint(1, 9999))
return np.float32(value)
def _elevation_mapper(noise_x, noise_y):
"""
Finds and returns the elevation noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 8, 0.9)
def _climate_mapper(y, noise_x, noise_y):
"""
Finds and returns the climate noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
# find distance from bottom of map and normalize to range [0, 1]
distance = np.sqrt((y - (ST.MAP_HEIGHT >> 1))**2) / ST.MAP_HEIGHT
value = _noise(noise_x, noise_y, 8, 0.7)
return (1.0 + value - distance) / 2.0
def _rainfall_mapper(noise_x, noise_y):
"""
Finds and returns the rainfall noise for the given noise_x and
noise_y parameters.
:param noise_x: noise_x = x / ST.MAP_WIDTH - randomizer
:param noise_y: noise_y = y / ST.MAP_HEIGHT - randomizer
:return: float
"""
return _noise(noise_x, noise_y, 4, 0.65, 2.5)
def create_map_arr():
"""
This function creates the elevation, climate, and rainfall noise maps,
normalizes them to the range [0, 1], and then assigns them to their
appropriate attributes in the singleton ST.
"""
# assign noise map values
randomizer = np.random.uniform(0.0001, 0.9999)
start_arr = timeit.default_timer()
X, Y = np.mgrid[0:ST.MAP_WIDTH, 0:ST.MAP_HEIGHT]
noise_x = X / ST.MAP_WIDTH - randomizer
noise_y = Y / ST.MAP_HEIGHT - randomizer
elevation_arr_np = _elevation_mapper(noise_x, noise_y)
climate_arr_np = _climate_mapper(Y, noise_x, noise_y)
rainfall_arr_np = _rainfall_mapper(noise_x, noise_y)
duration_arr = timeit.default_timer() - start_arr
start_loop = timeit.default_timer()
elevation_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
climate_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
rainfall_arr = np.zeros([ST.MAP_HEIGHT, ST.MAP_WIDTH], np.float32)
for y in range(ST.MAP_HEIGHT):
for x in range(ST.MAP_WIDTH):
noise_x = x / ST.MAP_WIDTH - randomizer
noise_y = y / ST.MAP_HEIGHT - randomizer
elevation_arr[y, x] = _elevation_mapper(noise_x, noise_y)
climate_arr[y, x] = _climate_mapper(y, noise_x, noise_y)
rainfall_arr[y, x] = _rainfall_mapper(noise_x, noise_y)
duration_loop = timeit.default_timer() - start_loop
print(np.allclose(elevation_arr, elevation_arr_np.T))
print(np.allclose(climate_arr, climate_arr_np.T))
print(np.allclose(rainfall_arr, rainfall_arr_np.T))
print("GENERATION TIME: loop: {:.6f}, array: {:.6f}".format(duration_loop, duration_arr))
if __name__ == "__main__":
create_map_arr()
The bottleneck is still in
value = np.array([noise.pnoise2(x, y, octaves, persistence, lacunarity, r)
for x, y, r in zip(noise_x.flat, noise_y.flat, rand_seed)])
and it would be highly favorable to use an implementation which supports 2D input, preferably from NumPy, directly (see further reading below).
Nevertheless, the modifications bring the execution time down to a third of the original time on my machine (which is not that powerful):
True
True
True
GENERATION TIME: loop: 338.094228, array: 101.549388
Those three True
s are from a little test I added to check if the generated maps are the same within reasonable accuracy. For this purpose the additional random value in _noise
was disabled.
Further reading
There have also already been similar questions on Code Review (see, e.g. here), where a reviewer created a Perlin noise implementation purely in Numpy. There also seems to be a GitHub project also doing Perlin noise with Numpy. So maybe have a look at them if your not forced to stick with noise
.
answered 5 hours ago
AlexAlex
653313
653313
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
add a comment |
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
$begingroup$
Thank you! I will take a look at the other ways to generate Perlin Noise. I was only using that library because it was the fastest I'd found so far.
$endgroup$
– LuminousNutria
4 hours ago
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216186%2fimproving-the-speed-of-creation-for-three-perlin-noise-maps-in-python%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
$begingroup$
Have a look at
numpy.meshgrid
and its examples. I think they'll do what you need.$endgroup$
– Austin Hastings
6 hours ago