Update
i try to follow this tutorial
but i dont know how can export to new tiff images slope/aspect with GDAL ?
the full code :
from __future__ import division
from osgeo import gdal
from matplotlib.colors import ListedColormap
from matplotlib import colors
import sys
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import math
filename = 'dem.tif'
def getResolution(rasterfn):
raster = gdal.Open(rasterfn)
geotransform = raster.GetGeoTransform()
res = {"east-west": abs(geotransform[1]),
"north-south": abs(geotransform[5])}
return res
def raster2array(rasterfn):
raster = gdal.Open(rasterfn)
band = raster.GetRasterBand(1)
return band.ReadAsArray()
def getNoDataValue(rasterfn):
raster = gdal.Open(rasterfn)
band = raster.GetRasterBand(1)
return band.GetNoDataValue()
data_array = raster2array(filename)
nodataval = getNoDataValue(filename)
resolution = getResolution(filename)
print(resolution)
print(nodataval)
print(type(data_array))
print(data_array.shape)
num_rows = data_array.shape[0]
num_cols = data_array.shape[1]
slope_array = np.ones_like(data_array) * nodataval
aspect_array = np.ones_like(data_array) * nodataval
for i in range(1, num_rows - 1):
for j in range(1, num_cols - 1):
a = data_array[i - 1][j - 1]
b = data_array[i - 1][j]
c = data_array[i - 1][j + 1]
d = data_array[i][j - 1]
e = data_array[i][j]
f = data_array[i][j + 1]
g = data_array[i + 1][j - 1]
h = data_array[i + 1][j]
q = data_array[i + 1][j + 1]
vals = [a, b, c, d, e, f, g, h, q]
if nodataval in vals:
all_present = False
else:
all_present = True
if all_present == True:
dz_dx = (c + (2 * f) + q - a - (2 * d) - g) / (8 * resolution['east-west'])
dz_dy = (g + (2 * h) + q - a - (2 * b) - c) / (8 * resolution['north-south'])
dz_dx_sq = math.pow(dz_dx, 2)
dz_dy_sq = math.pow(dz_dy, 2)
rise_run = math.sqrt(dz_dx_sq + dz_dy_sq)
slope_array[i][j] = math.atan(rise_run) * 57.29578
aspect = math.atan2(dz_dy, (-1 * dz_dx)) * 57.29578
if aspect < 0:
aspect_array[i][j] = 90 - aspect
elif aspect > 90:
aspect_array[i][j] = 360 - aspect + 90
else:
aspect_array[i][j] = 90 - aspect
hist, bins = np.histogram(slope_array, bins=100, range=(0, np.amax(slope_array)))
width = 0.7 * (bins[1] - bins[0])
center = (bins[:-1] + bins[1:]) / 2
plt.bar(center, hist, align='center', width=width)
plt.xlabel('Slope (degrees)')
plt.ylabel('Frequency')
plt.show()
color_map = ListedColormap(['white', 'darkgreen', 'green', 'limegreen', 'lime',
'greenyellow', 'yellow', 'gold',
'orange', 'orangered', 'red'])
# range begins at negative value so that missing values are white
color_bounds = list(range(-3, math.ceil(np.amax(slope_array)), 1))
color_norm = colors.BoundaryNorm(color_bounds, color_map.N)
#Create the plot and colorbar
img = plt.imshow(slope_array, cmap = color_map, norm = color_norm)
cbar = plt.colorbar(img, cmap = color_map, norm = color_norm,
boundaries = color_bounds, ticks = color_bounds)
#Show the visualization
plt.axis('off')
plt.title("Slope (degrees)")
plt.show()
plt.close()
first trial to export i follow this tutorial,but the slope in not correct
have lower degrees from the original(using gis program)
import gdal, ogr, os, osr
import numpy as np
def array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):
cols = array.shape[1]
rows = array.shape[0]
originX = rasterOrigin[0]
originY = rasterOrigin[1]
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create(newRasterfn, cols, rows, 1, gdal.GDT_Byte)
outRaster.SetGeoTransform((originX, pixelWidth, 0, originY, 0, pixelHeight))
outband = outRaster.GetRasterBand(1)
outband.WriteArray(array)
outRasterSRS = osr.SpatialReference()
outRasterSRS.ImportFromEPSG(4326)
outRaster.SetProjection(outRasterSRS.ExportToWkt())
outband.FlushCache()
def main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):
reversed_arr = slope_array # reverse array so the tif looks like the array
array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,reversed_arr) # convert array to raster
if __name__ == "__main__":
rasterOrigin = (-123.25745,45.43013)
pixelWidth = 10
pixelHeight = 10
newRasterfn = 'test.tif'
array = slope_array
main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array)
second trial i follow this quest but i dont take some export
def array_to_raster(slope_array):
"""Array > Raster
Save a raster from a C order array.
:param array: ndarray
"""
dst_filename = 'xxx.tiff'
x_pixels = num_rows # number of pixels in x
y_pixels = num_cols # number of pixels in y
driver = gdal.GetDriverByName('GTiff')
dataset = driver.Create(
dst_filename,
x_pixels,
y_pixels,
1,
gdal.GDT_Float32, )
dataset.GetRasterBand(1).WriteArray(array)
dataset.FlushCache() # Write to disk.
return dataset, dataset.GetRasterBand(1)
any idea
The error states exactly what the problem is. You are trying to multiply an int type by a NoneType (None). The most likely case is that nodataval is None, which would occur because the NoDataValue for filename's first raster band is not defined. Your print(nodataval) command should demonstrate that. Remember, printing None doesn't appear as the string 'None'. It appears as a blank or no character.
Your edits show that nodataval is None.
Related
I am new to solving a PDE and experimenting with a heat diffusion on a copper body of a rectangular ring shape using FiPy.
And this is a plot of simulation result at some times.
I am using the Grid2D() for a mesh and the CellVariable.constrain() to specify boundary conditions. The green dots are centers of exterior faces where T = 273.15 + 25 (K), and blue dots are centers of interior faces where T = 273.15 + 30 (K).
Obviously, I am doing something wrong, because the temperature goes down to 0K. How should I specify boundary conditions correctly?
These are the code.
import numpy as np
import matplotlib.pyplot as plt
import fipy
def get_mask_of_rect(mesh, x, y, w, h):
def left_id(i, j): return mesh.numberOfHorizontalFaces + i*mesh.numberOfVerticalColumns + j
def right_id(i, j): return mesh.numberOfHorizontalFaces + i*mesh.numberOfVerticalColumns + j + 1
def bottom_id(i, j): return i*mesh.nx + j
def top_id(i, j): return (i+1)*mesh.nx + j
j0, i0 = np.floor(np.array([x, y]) / [mesh.dx, mesh.dy]).astype(int)
n, m = np.round(np.array([w, h]) / [mesh.dx, mesh.dy]).astype(int)
mask = np.zeros_like(mesh.exteriorFaces, dtype=bool)
for i in range(i0, i0 + n):
mask[left_id(i, j0)] = mask[right_id(i, j0 + m-1)] = True
for j in range(j0, j0 + m):
mask[bottom_id(i0, j)] = mask[top_id(i0 + n-1, j)] = True
return mask
mesh = fipy.Grid2D(Lx = 1, Ly = 1, nx = 20, ny = 20) # Grid of size 1m x 1m
k_over_c_rho = 3.98E2 / (3.85E2 * 8.96E3) # The thermal conductivity, specific heat capacity, and density of Copper in MKS
dt = 0.1 * (mesh.dx**2 + mesh.dy**2) / (4*k_over_c_rho)
T0 = 273.15 # 0 degree Celsius in Kelvin
T = fipy.CellVariable(mesh, name='T', value=T0+25)
mask_e = mesh.exteriorFaces
T.constrain(T0+25., mask_e)
mask_i = get_mask_of_rect(mesh, 0.25, 0.25, 0.5, 0.5)
T.constrain(T0+30, mask_i)
eq = fipy.TransientTerm() == fipy.DiffusionTerm(coeff=k_over_c_rho)
viewer = fipy.MatplotlibViewer(vars=[T], datamin=0, datamax=400)
plt.ioff()
viewer._plot()
plt.plot(*mesh.faceCenters[:, mask_e], '.g')
plt.plot(*mesh.faceCenters[:, mask_i], '.b')
def update():
for _ in range(10):
eq.solve(var=T, dt=dt)
viewer._plot()
plt.draw()
timer = plt.gcf().canvas.new_timer(interval=50)
timer.add_callback(update)
timer.start()
plt.show()
.constrain() does not work for internal faces (see the warning at the end of Applying internal “boundary” conditions).
You can achieve an internal fixed value condition using sources, however. As a first cut, try
mask_i = get_mask_of_rect(mesh, 0.25, 0.25, 0.5, 0.5)
mask_i_cell = fipy.CellVariable(mesh, value=False)
mask_i_cell[mesh.faceCellIDs[..., mask_i]] = True
largeValue = 1e6
eq = (fipy.TransientTerm() == fipy.DiffusionTerm(coeff=k_over_c_rho)
- fipy.ImplicitSourceTerm(mask_i_cell * largeValue)
+ mask_i_cell * largeValue * (T0 + 30))
This constrains the cells on either side of the faces identified by mask_i to be at T0+30.
I am posting my own answer for future readers.
For boundary conditions for internal faces, you should use the implicit and explicit source terms on the equation, as in the jeguyer's answer.
By using source terms, you don't need to calculate a mask for faces, like this.(The get_mask_of_rect() in my question isn't required.)
T = fipy.CellVariable(mesh, name = 'T', value = T0 + 25)
mask_e = mesh.exteriorFaces
T.constrain(T0 + 25., mask_e)
mask_i_cell = (
(0.25 < mesh.x) & (mesh.x < 0.25 + 0.5) &
(0.25 < mesh.y) & (mesh.y < 0.25 + 0.5)
)
large_value = 1E6
eq = fipy.TransientTerm() == (
fipy.DiffusionTerm(coeff = k_over_c_rho) -
fipy.ImplicitSourceTerm(mask_i_cell * large_value) +
mask_i_cell * (large_value * (T0 + 30) # explicit source
))
viewer = fipy.MatplotlibViewer(vars = [T], datamin = T0, datamax = T0+50)
I'm using a thermal camera with Python code on my Raspberry Pi. I inserted some code yesterday that'll allow me to find the radius of where a fire is on the thermal camera and I'm going to output the theta in a different code.
What I'm having trouble with however is showcasing one output rather than a consistent output every second (or in respect to the refresh rate). Is there a way to accomplish this?
Here is my code below:
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
import math
extent = (-16, 16, -12.5, 12.5)
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)
mlx = adafruit_mlx90640.MLX90640(i2c)
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_1_HZ
mlx_shape = (24,32)
plt.ion()
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0, vmax=60, extent=extent)
cbar = fig.colorbar(therm1)
cbar.set_label('Temperature [$^{\circ}$C]', fontsize=14)
frame = np.zeros((2432,))
t_array = []
np.array
print("Starting loop")
while True:
t1 = time.monotonic()
try:
mlx.getFrame(frame)
data_array = (np.reshape(frame,mlx_shape))
therm1.set_data(np.reshape(frame,mlx_shape))
therm1.set_clim(vmin=np.min(data_array))
cbar.update_normal(therm1)
plt.title("Max")
plt.pause(0.001)
t_array.append(time.monotonic() - t1)
# fig.savefig('mlx90640_test_fliplr.png', dpi=300, facecolor = '#FCFCFC', bbox_inches='tight')
highest_num = data_array[0][0]
x = 0
y = 0
for i in range (len(data_array)):
for j in range(len(data_array[i])):
if data_array[x][y] < data_array[i][j]:
x = i
y = j
highest_num = data_array[i][j]
idx = np.argmax(data_array)
m, n = len(data_array), len(data_array[0])
r, c = m - (idx // n) - 1 , idx % n
y, x = r - (m // 2), c - (n // 2)
radius = math.sqrt( x x + y * y)
theta = math.atan(y/x)
theta = 180 * theta/math.pi
print("Radius", radius)
except ValueError:
continue
I need to make a mask of hexagonal packed disks. The code below does the job, but I don't feel like its efficient. I'm learning python as well so I'd love to get some expert advice on how to do this more computationally efficient.
r = 0.01
X, Y = np.mgrid[0:1:1000j, 0:1:1000j]
mask = np.full(X.shape, False)
px, py = np.mgrid[r : 1 : 2 * r * np.sqrt(3), r : 1 + r + np.finfo(float).eps: 2 * r]
px = np.vstack((px, px + r * np.sqrt(3)))
py = np.vstack((py, py - r))
fig, ax = plt.subplots(figsize= (12, 12), dpi=50)
img = ax.imshow(mask * 1, cmap = 'gray', vmin = 0, vmax = 1, extent = [0, 1, 0, 1])
for i, _ in np.ndenumerate(px): #is this loop dumb and inefficient?
C = (X - px[i]) ** 2 + (Y - py[i]) ** 2
mask = mask | (C < r ** 2)
img.set_data(mask * 1)
ax.set_aspect(1)
In particular, is there a way to vectorize the for loop?
Thanks
It may be efficient to create a single tile of the pattern, and then repeat it horizontally and vertically as needed:
Create a tile:
import numpy as np
import matplotlib.pyplot as plt
r = 0.01
sq3 = np.sqrt(3)
samples = 1000
X, Y = np.mgrid[1:(1 + 2 * sq3):int(sq3 * samples) * 1j, 0:2:samples * 1j]
XY = np.c_[X.flatten(), Y.flatten()]
# coordinates of centers of disks; suffices to take disks of radius 1 here
p = np.array([[1, 1], [(1 + sq3), 0], [(1 + sq3), 2], [(1 + 2 * sq3), 1]])
# compute the distance from each point of XY to each disk center
dist = (XY**2).sum(axis=1).reshape(-1, 1) + (p**2).sum(axis=1) - 2 * (XY # p.T)
# mask points outside the disks
tile = (np.min(dist, axis=1) < 1).reshape(X.shape)
fig, ax = plt.subplots(figsize=(5, 5))
ax.set_aspect(1)
plt.imshow(tile, extent=[0, 2 * r, r, (1 + 2 * sq3) * r]);
It gives:
Repeat the tile:
# the number of times to repeat the tile in the horizontal and vertical directions
h, w = 20, 30
# donwsample the tile as needed and replicate
sample_rate = 10
mask = np.tile(tile[::sample_rate, ::sample_rate], (h, w))
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect(1)
ax.imshow(mask, extent=[0, 2 * r * w, 0, 2 * sq3 * r * h]);
This gives:
I am going to solve 1D FitzHugh Nagoma with homogeneous Neumann boundary conditions.
How to plot U and V separately. Here a1=2, a0=-0.03 , ep= 0.01 Du= 1, Dv=4 I was confused by plotting the figure
U_t=Du U_xx +U -U^3 - V
V_t=Dv V_xx + ep(U-a1V - a0)
import numpy as np
import matplotlib.pyplot as plt
#matplotlib inline
Du = 0.001
Dv = 0.005
tau = 1
k = -.00
ep = 0.01
a1 = 2
a0 = -0.03
L = 2
N= 10
x = np.linspace(0, L, N+1)
dx = x[1]-x[0]
T = 45 # total time
dt = .01 # time step
size = N
n = int(T / dt) # number of iterations
U = np.random.rand(size)
V = np.random.rand(size)
def laplacian(Z):
Ztop = Z[0:-2]
Zbottom = Z[2:]
Zcenter = Z[1:-1]
return (Ztop + Zbottom -
2 * Zcenter) / dx**2
def show_patterns(U, ax=None):
ax.imshow(U, cmap=plt.cm.copper,
interpolation='bilinear',
extent=[-1, 1])
ax.set_axis_off()
fig, axes = plt.subplots(3, 3, figsize=(16, 16))
step_plot = n // 9
# We simulate the PDE with the finite difference
# method.
for i in range(n):
# We compute the Laplacian of u and v.
deltaU = laplacian(U)
deltaV = laplacian(V)
# We take the values of u and v inside the grid.
Uc = U[1:-1]
Vc = V[1:-1]
# We update the variables.
U[1:-1], V[1:-1] = \
Uc + dt * (Du * deltaU + Uc - Uc**3 - Vc),\
Vc + dt * (Dv * deltaV + ep*(Uc - a1*Vc - a0)) / tau
# Neumann conditions: derivatives at the edges
# are null.
for Z in (U, V):
Z[0] = Z[1]
Z[-1] = Z[-2]
# Z[:, 0] = Z[:, 1]
# Z[:, -1] = Z[:, -2]
# We plot the state of the system at
# 9 different times.
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
show_patterns(U,ax=None)
I got an error 'NoneType' object has no attribute 'imshow'
and could not solve it
This line
show_patterns(U,ax=None)
passed in a None to the ax parameter.
I don't know what ax should be but it needs to be properly initialised.
I am trying to model random closed packing spheres of uniform size in a square using python. And the spheres should not overlap but I do not know how to do this
I have so far:
Code:
import random, math, pylab
def show_conf(L, sigma, title, fname):
pylab.axes()
for [x, y] in L:
for ix in range(-1, 2):
for iy in range(-1, 2):
cir = pylab.Circle((x + ix, y + iy), radius=sigma, fc='r')
pylab.gca().add_patch(cir)
pylab.axis('scaled')
pylab.xlabel('eixo x')
pylab.ylabel('eixo y')
pylab.title(title)
pylab.axis([0.0, 1.0, 0.0, 1.0])
pylab.savefig(fname)
pylab.close()
L = []
N = 8 ** 2
for i in range(N):
posx = float(random.uniform(0, 1))
posy = float(random.uniform(0, 1))
L.append([posx, posy])
print L
N = 8 ** 2
eta = 0.3
sigma = math.sqrt(eta / (N * math.pi))
Q = 20
ltilde = 5*sigma
N_sqrt = int(math.sqrt(N) + 0.5)
titulo1 = '$N=$'+str(N)+', $\eta =$'+str(eta)
nome1 = 'inicial'+'_N_'+str(N) + '_eta_'+str(eta) + '.png'
show_conf(L, sigma, titulo1, nome1)
This is a very hard problem (and probably np-hard). There should be a lot of ressources available.
Before i present some more general approach, check out this wikipedia-site for an overview of the currently best known packing-patterns for some N (N circles in a square).
You are lucky that there is an existing circle-packing implementation in python (heuristic!) which is heavily based on modern optimization-theory (difference of convex-functions + Concave-convex-procedure).
The method used is described here (academic paper & link to software; 2016!)
The software package used is here
There is an example directory with circle_packing.py (which is posted below together with the output)
The following example also works for circles of different shapes
Example taken from the above software-package (example by Xinyue Shen)
__author__ = 'Xinyue'
from cvxpy import *
import numpy as np
import matplotlib.pyplot as plt
import dccp
n = 10
r = np.linspace(1,5,n)
c = Variable(n,2)
constr = []
for i in range(n-1):
for j in range(i+1,n):
constr.append(norm(c[i,:]-c[j,:])>=r[i]+r[j])
prob = Problem(Minimize(max_entries(max_entries(abs(c),axis=1)+r)), constr)
#prob = Problem(Minimize(max_entries(normInf(c,axis=1)+r)), constr)
prob.solve(method = 'dccp', ccp_times = 1)
l = max_entries(max_entries(abs(c),axis=1)+r).value*2
pi = np.pi
ratio = pi*sum_entries(square(r)).value/square(l).value
print "ratio =", ratio
print prob.status
# plot
plt.figure(figsize=(5,5))
circ = np.linspace(0,2*pi)
x_border = [-l/2, l/2, l/2, -l/2, -l/2]
y_border = [-l/2, -l/2, l/2, l/2, -l/2]
for i in xrange(n):
plt.plot(c[i,0].value+r[i]*np.cos(circ),c[i,1].value+r[i]*np.sin(circ),'b')
plt.plot(x_border,y_border,'g')
plt.axes().set_aspect('equal')
plt.xlim([-l/2,l/2])
plt.ylim([-l/2,l/2])
plt.show()
Output
Modification for your task: equal-sized circles
Just replace:
r = np.linspace(1,5,n)
With:
r = [1 for i in range(n)]
Output
Fun example with 64 circles (this will take some time!)
If you would like a more updated version of #leopold.talirz solution, I suggest you use the following:
from cvxpy import *
import numpy as np
import matplotlib.pyplot as plt
import dccp
n = 10
r = np.linspace(1,5,n)
c = Variable(shape=(n,2))
constr = []
for i in range(n-1):
for j in range(i+1,n):
constr.append(norm(c[i,:]-c[j,:])>=r[i]+r[j])
prob = Problem(Minimize(max(max(abs(c),axis=1)+r)), constr)
#prob = Problem(Minimize(max_entries(normInf(c,axis=1)+r)), constr)
prob.solve(method = 'dccp', ccp_times = 1)
l = max(max(abs(c),axis=1)+r).value*2
pi = np.pi
ratio = pi*sum(square(r)).value/square(l).value
print("ratio =", ratio)
print(prob.status)
# plot
plt.figure(figsize=(5,5))
circ = np.linspace(0,2*pi)
x_border = [-l/2, l/2, l/2, -l/2, -l/2]
y_border = [-l/2, -l/2, l/2, l/2, -l/2]
for i in range(n):
plt.plot(c[i,0].value+r[i]*np.cos(circ),c[i,1].value+r[i]*np.sin(circ),'b')
plt.plot(x_border,y_border,'g')
plt.axes().set_aspect('equal')
plt.xlim([-l/2,l/2])
plt.ylim([-l/2,l/2])
plt.show()