ACO algorithm on python machine learning - python

I am trying to understand the code below where it shows the default TSP path on a picture. I understand most of the part except for the polyfit_plot() function. I understand the function in it separately but when combine together I just don't get what it contributes to. I have even tried to delete the function and the result is actually the same, and I don't see where the function is implemented in. Can someone explain it to me?
import numpy as np
import math
import random
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
united_states_map = mpimg.imread(r"C:\Users\user\Downloads\archive\united_states_map.png")
def show_cities(path, w=12, h=8):
if isinstance(path, dict): path = list(path.values())
if isinstance(path[0][0], str): path = [ item[1] for item in path ]
plt.imshow(united_states_map)
for x0, y0 in path:
plt.plot(x0, y0, 'y*', markersize=15) # y* = yellow star for starting point
plt.axis("off")
fig = plt.gcf()
fig.set_size_inches([w, h])
def show_path(path, starting_city=None, w=12, h=8):
if isinstance(path, dict): path = list(path.values())
if isinstance(path[0][0], str): path = [ item[1] for item in path ]
starting_city = starting_city or path[0]
x, y = list(zip(*path))
#_, (x0, y0) = starting_city
(x0, y0) = starting_city
plt.imshow(united_states_map)
#plt.plot(x0, y0, 'y*', markersize=15) # y* = yellow star for starting point
plt.plot(x + x[:1], y + y[:1]) # include the starting point at the end of path
plt.axis("off")
fig = plt.gcf()
fig.set_size_inches([w, h])
def polyfit_plot(x,y,deg, **kwargs):
coefficients = np.polyfit(x,y,deg,**kwargs)
poly = np.poly1d(coefficients)
new_x = np.linspace(x[0], x[-1])
new_y = poly(new_x)
plt.plot(x, y, "o", new_x, new_y)
plt.xlim([x[0]-1, x[-1] + 1 ])
terms = []
for p, c in enumerate(reversed(coefficients)):
term = str(round(c,1))
if p == 1: term += 'x'
if p >= 2: term += 'x^'+str(p)
terms.append(term)
plt.title(" + ".join(reversed(terms)))
cities = { "Oklahoma City": (392.8, 356.4), "Montgomery": (559.6, 404.8), "Saint Paul": (451.6, 186.0), "Trenton": (698.8, 239.6), "Salt Lake City": (204.0, 243.2), "Columbus": (590.8, 263.2), "Austin": (389.2, 448.4), "Phoenix": (179.6, 371.2), "Hartford": (719.6, 205.2), "Baton Rouge": (489.6, 442.0), "Salem": (80.0, 139.2), "Little Rock": (469.2, 367.2), "Richmond": (673.2, 293.6), "Jackson": (501.6, 409.6), "Des Moines": (447.6, 246.0), "Lansing": (563.6, 216.4), "Denver": (293.6, 274.0), "Boise": (159.6, 182.8), "Raleigh": (662.0, 328.8), "Atlanta": (585.6, 376.8), "Madison": (500.8, 217.6), "Indianapolis": (548.0, 272.8), "Nashville": (546.4, 336.8), "Columbia": (632.4, 364.8), "Providence": (735.2, 201.2), "Boston": (738.4, 190.8), "Tallahassee": (594.8, 434.8), "Sacramento": (68.4, 254.0), "Albany": (702.0, 193.6), "Harrisburg": (670.8, 244.0) }
cities = list(sorted(cities.items()))
print(len(cities))
show_cities(cities)
show_path(cities)

It seems that the function polyfit_plot is unused in the code, so it is never run and as you say it does not affect the outcome.

Related

why can I model some of these ellipses with skimage and not others?

I am cross-posting this from GitHub as I am not sure whether the issue is a problem with my data or a bug.
https://github.com/scikit-image/scikit-image/issues/6699
I have thousands of elliptical features in my microscopy data that I want to fit models to using skimage. The model fails on some for no obvious reason. Here's code to reproduce:
import numpy as np
from skimage.measure import EllipseModel
import plotly.express as px
good_x1 = [779.026, 778.125, 776.953, 776.195, 775.617, 775.068, 774.127, 773.696, 773.305, 773.113, 773.088, 773.233, 773.449, 773.913, 774.344, 774.625, 775.179, 775.777, 776.254, 777.039, 777.926, 778.945, 780.023, 781.059, 781.973, 782.777, 783.244, 783.922, 784.995, 785.825, 786.196, 786.486, 786.65, 786.614, 786.482, 786.153, 785.749, 785.507, 784.901, 784.482, 783.879, 782.809, 781.965, 780.998, 780.001, 779.026]
good_y1 = [309.143, 309.432, 309.912, 310.35, 310.46, 311.087, 312.099, 312.879, 314.085, 315.012, 315.995, 316.948, 318.166, 319.044, 319.751, 320.283, 320.794, 321.34, 321.505, 321.908, 322.254, 322.478, 322.467, 322.243, 321.929, 321.561, 321.449, 320.891, 319.995, 318.905, 318.07, 316.872, 315.97, 315.037, 313.883, 312.943, 312.17, 311.623, 311.093, 310.477, 310.151, 309.54, 309.18, 309.027, 309.022, 309.143]
good_x2 = [434.959, 434.0, 433.012, 432.093, 430.938, 430.279, 429.847, 429.535, 429.257, 429.031, 428.843, 429.0, 429.348, 429.872, 430.313, 431.048, 432.189, 433.043, 434.003, 434.971, 435.769, 436.199, 436.743, 437.263, 437.824, 438.017, 438.018, 437.831, 437.449, 437.29, 436.807, 436.255, 435.776, 434.959]
good_y2 = [215.849, 216.001, 215.929, 215.684, 215.09, 214.615, 214.117, 213.631, 212.903, 211.992, 211.017, 210.0, 209.39, 208.857, 208.587, 208.087, 207.57, 207.247, 207.135, 207.2, 207.565, 207.73, 208.248, 208.819, 210.055, 210.998, 212.001, 212.952, 213.687, 214.168, 214.781, 215.333, 215.49, 215.849]
good_x3 = [1666.998, 1666.014, 1665.206, 1664.689, 1664.302, 1663.977, 1663.969, 1664.293, 1664.527, 1665.09, 1665.929, 1667.048, 1668.016, 1668.658, 1669.171, 1669.638, 1669.599, 1668.995, 1667.916, 1666.998]
good_y3 = [85.023, 85.07, 85.414, 85.685, 86.245, 86.994, 88.004, 88.835, 89.364, 89.862, 90.302, 90.338, 90.034, 89.491, 89.134, 87.917, 86.807, 86.004, 85.251, 85.023]
bad_x1 = [1541.221, 1541.848, 1543.009, 1544.15, 1544.962, 1545.777, 1545.943, 1545.786, 1545.103, 1543.986, 1543.14, 1541.968, 1541.094, 1540.765, 1540.799, 1541.221]
bad_y1 = [1254.78, 1255.29, 1255.535, 1255.395, 1254.945, 1253.922, 1253.0, 1252.063, 1250.892, 1250.374, 1250.401, 1250.959, 1252.049, 1252.968, 1254.069, 1254.78]
bad_x2 = [1739.079, 1738.567, 1738.392, 1738.118, 1738.17, 1738.782, 1739.302, 1740.179, 1741.013, 1741.999, 1742.997, 1743.423, 1744.178, 1743.811, 1743.735, 1743.595, 1743.308, 1742.834, 1742.342, 1741.813, 1740.998, 1739.995, 1739.079]
bad_y2 = [329.807, 329.316, 328.814, 327.989, 327.061, 325.853, 325.22, 324.478, 324.115, 324.078, 324.154, 324.49, 324.753, 325.994, 326.902, 327.679, 328.143, 328.836, 329.41, 329.628, 329.99, 330.067, 329.807]
bad_x3 = [992.001, 991.057, 989.879, 989.599, 989.252, 989.286, 989.894, 991.05, 991.983, 992.806, 993.286, 993.846, 994.32, 994.481, 994.088, 992.959, 992.001]
bad_y3 = [136.048, 136.19, 136.883, 137.551, 138.053, 138.929, 140.102, 140.767, 140.846, 140.551, 140.416, 139.851, 139.115, 137.938, 136.94, 136.168, 136.048]
xy = [(good_x1, good_y1, 'good_1'), (good_x2, good_y2, 'good_2'), (good_x3, good_y3, 'good_3'),
(bad_x1, bad_y1, 'bad_1'), (bad_x2, bad_y2, 'bad_2'), (bad_x3, bad_y3, 'bad_3')]
for ii in xy:
points = list(zip(ii[0], ii[1]))
a_points = np.array(points)
model = EllipseModel()
if model.estimate(a_points) == False:
fig = px.line(x= ii[0], y= ii[1], title='model fitting failed for ' + ii[2])
fig.show()
try:
xc, yc, a, b, theta = model.params
print(model.params)
ellipse_centre = (xc, yc)
residuals = model.residuals(a_points)
print(residuals)
except Exception as e: print(e)
else:
fig = px.line(x= ii[0], y= ii[1], title='model fitting successful for ' + ii[2])
fig.show()
xc, yc, a, b, theta = model.params
print(model.params)
ellipse_centre = (xc, yc)
residuals = model.residuals(a_points)
print(residuals)
Visually these features all seem elliptical and there is no difference between them in the length of the point lists or other properties. I think it's a bug but would appreciate a 2nd opinion, thanks.
Addition 2023-01-25:
There is another implementation of the same algorithm underlying the skimage function at SciPy, here: https://scipython.com/blog/direct-linear-least-squares-fitting-of-an-ellipse/
I have tested this on the same data and it variously fits, misfits or throws errors on my sets of points. Interesting it does this in a slightly different pattern to the skimage function. I think this problem is a fundamental flaw in the algorithm and not a bug.
Your x, y data points differ from their means by only a small amount, so the algorithms you are using are running into numerical errors which lead to failures in the linear algebra routines used in the fitting process.
You can solve this by subtracting off the means (i.e. spatially shifting the ellipses) so that there is a greater relative difference between the values: e.g. the following works for me:
import numpy as np
from skimage.measure import EllipseModel
import plotly.express as px
good_x1 = [779.026, 778.125, 776.953, 776.195, 775.617, 775.068, 774.127, 773.696, 773.305, 773.113, 773.088, 773.233, 773.449, 773.913, 774.344, 774.625, 775.179, 775.777, 776.254, 777.039, 777.926, 778.945, 780.023, 781.059, 781.973, 782.777, 783.244, 783.922, 784.995, 785.825, 786.196, 786.486, 786.65, 786.614, 786.482, 786.153, 785.749, 785.507, 784.901, 784.482, 783.879, 782.809, 781.965, 780.998, 780.001, 779.026]
good_y1 = [309.143, 309.432, 309.912, 310.35, 310.46, 311.087, 312.099, 312.879, 314.085, 315.012, 315.995, 316.948, 318.166, 319.044, 319.751, 320.283, 320.794, 321.34, 321.505, 321.908, 322.254, 322.478, 322.467, 322.243, 321.929, 321.561, 321.449, 320.891, 319.995, 318.905, 318.07, 316.872, 315.97, 315.037, 313.883, 312.943, 312.17, 311.623, 311.093, 310.477, 310.151, 309.54, 309.18, 309.027, 309.022, 309.143]
good_x2 = [434.959, 434.0, 433.012, 432.093, 430.938, 430.279, 429.847, 429.535, 429.257, 429.031, 428.843, 429.0, 429.348, 429.872, 430.313, 431.048, 432.189, 433.043, 434.003, 434.971, 435.769, 436.199, 436.743, 437.263, 437.824, 438.017, 438.018, 437.831, 437.449, 437.29, 436.807, 436.255, 435.776, 434.959]
good_y2 = [215.849, 216.001, 215.929, 215.684, 215.09, 214.615, 214.117, 213.631, 212.903, 211.992, 211.017, 210.0, 209.39, 208.857, 208.587, 208.087, 207.57, 207.247, 207.135, 207.2, 207.565, 207.73, 208.248, 208.819, 210.055, 210.998, 212.001, 212.952, 213.687, 214.168, 214.781, 215.333, 215.49, 215.849]
good_x3 = [1666.998, 1666.014, 1665.206, 1664.689, 1664.302, 1663.977, 1663.969, 1664.293, 1664.527, 1665.09, 1665.929, 1667.048, 1668.016, 1668.658, 1669.171, 1669.638, 1669.599, 1668.995, 1667.916, 1666.998]
good_y3 = [85.023, 85.07, 85.414, 85.685, 86.245, 86.994, 88.004, 88.835, 89.364, 89.862, 90.302, 90.338, 90.034, 89.491, 89.134, 87.917, 86.807, 86.004, 85.251, 85.023]
bad_x1 = [1541.221, 1541.848, 1543.009, 1544.15, 1544.962, 1545.777, 1545.943, 1545.786, 1545.103, 1543.986, 1543.14, 1541.968, 1541.094, 1540.765, 1540.799, 1541.221]
bad_y1 = [1254.78, 1255.29, 1255.535, 1255.395, 1254.945, 1253.922, 1253.0, 1252.063, 1250.892, 1250.374, 1250.401, 1250.959, 1252.049, 1252.968, 1254.069, 1254.78]
bad_x2 = [1739.079, 1738.567, 1738.392, 1738.118, 1738.17, 1738.782, 1739.302, 1740.179, 1741.013, 1741.999, 1742.997, 1743.423, 1744.178, 1743.811, 1743.735, 1743.595, 1743.308, 1742.834, 1742.342, 1741.813, 1740.998, 1739.995, 1739.079]
bad_y2 = [329.807, 329.316, 328.814, 327.989, 327.061, 325.853, 325.22, 324.478, 324.115, 324.078, 324.154, 324.49, 324.753, 325.994, 326.902, 327.679, 328.143, 328.836, 329.41, 329.628, 329.99, 330.067, 329.807]
bad_x3 = [992.001, 991.057, 989.879, 989.599, 989.252, 989.286, 989.894, 991.05, 991.983, 992.806, 993.286, 993.846, 994.32, 994.481, 994.088, 992.959, 992.001]
bad_y3 = [136.048, 136.19, 136.883, 137.551, 138.053, 138.929, 140.102, 140.767, 140.846, 140.551, 140.416, 139.851, 139.115, 137.938, 136.94, 136.168, 136.048]
xy = [(good_x1, good_y1, 'good_1'), (good_x2, good_y2, 'good_2'), (good_x3, good_y3, 'good_3'),
(bad_x1, bad_y1, 'bad_1'), (bad_x2, bad_y2, 'bad_2'), (bad_x3, bad_y3, 'bad_3')]
for ii in xy:
x = np.array(ii[0])
y = np.array(ii[1])
x = x - np.mean(x)
y = y - np.mean(y)
points = list(zip(x, y))
a_points = np.array(points)
model = EllipseModel()
if model.estimate(a_points) == False:
fig = px.line(x=x, y=y, title='model fitting failed for ' + ii[2])
fig.show()
try:
xc, yc, a, b, theta = model.params
print(model.params)
ellipse_centre = (xc, yc)
residuals = model.residuals(a_points)
print(residuals)
except Exception as e: print(e)
else:
fig = px.line(x=x, y=y, title='model fitting successful for ' + ii[2])
fig.show()
xc, yc, a, b, theta = model.params
print(model.params)
ellipse_centre = (xc, yc)
residuals = model.residuals(a_points)
print(residuals)

How to draw such a picture with Python? [duplicate]

I make following Python Code to calculate center and size of Gaussian-like distribution basis of moment method. But, I can't make the code to calculate the angle of gaussian.
Please look at pictures.
First Picture is original data.
Second picture is reconstruct data from the result of moment method.
But, second picture is insufficient reconstruction. Because, original data is inclined distribution.
I have to, I think, calculate the angle of axis for Gaussian-like distribution.
To assume that the original distribution is sufficiently Gaussian-like distribution.
import numpy as np
import matplotlib.pyplot as plt
import json, glob
import sys, time, os
from mpl_toolkits.axes_grid1 import make_axes_locatable
from linecache import getline, clearcache
from scipy.integrate import simps
from scipy.constants import *
def integrate_simps (mesh, func):
nx, ny = func.shape
px, py = mesh[0][int(nx/2), :], mesh[1][:, int(ny/2)]
val = simps( simps(func, px), py )
return val
def normalize_integrate (mesh, func):
return func / integrate_simps (mesh, func)
def moment (mesh, func, index):
ix, iy = index[0], index[1]
g_func = normalize_integrate (mesh, func)
fxy = g_func * mesh[0]**ix * mesh[1]**iy
val = integrate_simps (mesh, fxy)
return val
def moment_seq (mesh, func, num):
seq = np.empty ([num, num])
for ix in range (num):
for iy in range (num):
seq[ix, iy] = moment (mesh, func, [ix, iy])
return seq
def get_centroid (mesh, func):
dx = moment (mesh, func, (1, 0))
dy = moment (mesh, func, (0, 1))
return dx, dy
def get_weight (mesh, func, dxy):
g_mesh = [mesh[0]-dxy[0], mesh[1]-dxy[1]]
lx = moment (g_mesh, func, (2, 0))
ly = moment (g_mesh, func, (0, 2))
return np.sqrt(lx), np.sqrt(ly)
def plot_contour_sub (mesh, func, loc=[0, 0], title="name", pngfile="./name"):
sx, sy = loc
nx, ny = func.shape
xs, ys = mesh[0][0, 0], mesh[1][0, 0]
dx, dy = mesh[0][0, 1] - mesh[0][0, 0], mesh[1][1, 0] - mesh[1][0, 0]
mx, my = int ( (sy-ys)/dy ), int ( (sx-xs)/dx )
fig, ax = plt.subplots()
divider = make_axes_locatable(ax)
ax.set_aspect('equal')
ax_x = divider.append_axes("bottom", 1.0, pad=0.5, sharex=ax)
ax_x.plot (mesh[0][mx, :], func[mx, :])
ax_x.set_title ("y = {:.2f}".format(sy))
ax_y = divider.append_axes("right" , 1.0, pad=0.5, sharey=ax)
ax_y.plot (func[:, my], mesh[1][:, my])
ax_y.set_title ("x = {:.2f}".format(sx))
im = ax.contourf (*mesh, func, cmap="jet")
ax.set_title (title)
plt.colorbar (im, ax=ax, shrink=0.9)
plt.savefig(pngfile + ".png")
def make_gauss (mesh, sxy, rxy, rot):
x, y = mesh[0] - sxy[0], mesh[1] - sxy[1]
px = x * np.cos(rot) - y * np.sin(rot)
py = y * np.cos(rot) + x * np.sin(rot)
fx = np.exp (-0.5 * (px/rxy[0])**2)
fy = np.exp (-0.5 * (py/rxy[1])**2)
return fx * fy
if __name__ == "__main__":
argvs = sys.argv
argc = len(argvs)
print (argvs)
nx, ny = 500, 500
lx, ly = 200, 150
rx, ry = 40, 25
sx, sy = 50, 10
rot = 30
px = np.linspace (-1, 1, nx) * lx
py = np.linspace (-1, 1, ny) * ly
mesh = np.meshgrid (px, py)
fxy0 = make_gauss (mesh, [sx, sy], [rx, ry], np.deg2rad(rot)) * 10
s0xy = get_centroid (mesh, fxy0)
w0xy = get_weight (mesh, fxy0, s0xy)
fxy1 = make_gauss (mesh, s0xy, w0xy, np.deg2rad(0))
s1xy = get_centroid (mesh, fxy1)
w1xy = get_weight (mesh, fxy1, s1xy)
print ([sx, sy], s0xy, s1xy)
print ([rx, ry], w0xy, w1xy)
plot_contour_sub (mesh, fxy0, loc=s0xy, title="Original", pngfile="./fxy0")
plot_contour_sub (mesh, fxy1, loc=s1xy, title="Reconst" , pngfile="./fxy1")
As Paul Panzer said, the flaw of your approach is that you look for "weight" and "angle" instead of covariance matrix. The covariance matrix fits perfectly in your approach: just compute one more moment, mixed xy.
The function get_weight should be replaced with
def get_covariance (mesh, func, dxy):
g_mesh = [mesh[0]-dxy[0], mesh[1]-dxy[1]]
Mxx = moment (g_mesh, func, (2, 0))
Myy = moment (g_mesh, func, (0, 2))
Mxy = moment (g_mesh, func, (1, 1))
return np.array([[Mxx, Mxy], [Mxy, Myy]])
Add one more import,
from scipy.stats import multivariate_normal
for reconstruction purpose. Still using your make_gauss function to create the original PDF, this is how it now gets reconstructed:
s0xy = get_centroid (mesh, fxy0)
w0xy = get_covariance (mesh, fxy0, s0xy)
fxy1 = multivariate_normal.pdf(np.stack(mesh, -1), mean=s0xy, cov=w0xy)
That's it; reconstruction works fine now.
Units on the color bar are not the same, because your make_gauss formula does not normalize the PDF.

matplotlib figure parameters don't appears

Here is my issue: I have an embedded matplotlib figure in a Qt5 application. When I press the button "edit axis, curve and image parameter", I select my concerned subplot, but only the tab "axis" options appears. it is missing tabs for "curve" and "image".
actual picture
whereas I should have had something like this:
targeted picture
If anyone knows why...
Probably the answer is easy:
If there is no curve (line) in the plot, there will be no "Curves" tab.
If there is no image in the plot, there will be no "Images" tab.
class View2D(MapView):
def show(self, som, what='codebook', which_dim='all', cmap=None,
col_sz=None, desnormalize=False):
(self.width, self.height, indtoshow, no_row_in_plot, no_col_in_plot,
axis_num) = self._calculate_figure_params(som, which_dim, col_sz)
self.prepare()
if not desnormalize:
codebook = som.codebook.matrix
else:
codebook = som._normalizer.denormalize_by(som.data_raw, som.codebook.matrix)
if which_dim == 'all':
names = som._component_names[0]
elif type(which_dim) == int:
names = [som._component_names[0][which_dim]]
elif type(which_dim) == list:
names = som._component_names[0][which_dim]
while axis_num < len(indtoshow):
axis_num += 1
ax = plt.subplot(no_row_in_plot, no_col_in_plot, axis_num)
ind = int(indtoshow[axis_num-1])
min_color_scale = np.mean(codebook[:, ind].flatten()) - 1 * np.std(codebook[:, ind].flatten())
max_color_scale = np.mean(codebook[:, ind].flatten()) + 1 * np.std(codebook[:, ind].flatten())
min_color_scale = min_color_scale if min_color_scale >= min(codebook[:, ind].flatten()) else \
min(codebook[:, ind].flatten())
max_color_scale = max_color_scale if max_color_scale <= max(codebook[:, ind].flatten()) else \
max(codebook[:, ind].flatten())
norm = matplotlib.colors.Normalize(vmin=min_color_scale, vmax=max_color_scale, clip=True)
mp = codebook[:, ind].reshape(som.codebook.mapsize[0],
som.codebook.mapsize[1])
# pl = plt.pcolor(mp[::-1], norm=norm, cmap='jet')
pl = plt.imshow(mp[::-1], interpolation='nearest', origin='lower',cmap='jet')
plt.axis([0, som.codebook.mapsize[1], 0, som.codebook.mapsize[0]])
plt.title(names[axis_num - 1])
ax.set_yticklabels([])
ax.set_xticklabels([])
plt.colorbar(pl)
plt.show()

Interactively update color in Mayavi, Python

It is my first post on StackOverflow.
I am writing a Mayavi Python program. Could anybody tell me how to update/modify the color of a point interactively? For example, in points3d(), changing the color of a point in real-time when I interactively modify its position.
I tried to do something under #on_trait_change, but it doesn't work. Color cannot be changed.
The following is my code:
import mayavi
import mayavi.mlab
from numpy import arange, pi, cos, sin
from traits.api import HasTraits, Range, Instance, \
on_trait_change
from traitsui.api import View, Item, HGroup
from mayavi.core.api import PipelineBase
from mayavi.core.ui.api import MayaviScene, SceneEditor, \
MlabSceneModel
def luc_func(x, y, z):
return x + y + z;
class Visualization(HasTraits):
x1 = Range(1, 30, 5)
z1 = Range(1, 30, 5)
scene = Instance(MlabSceneModel, ())
def __init__(self):
# Do not forget to call the parent's __init__
HasTraits.__init__(self)
z = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
y = [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5]
x = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
self.plot = self.scene.mlab.points3d(x, y, z, luc_func, scale_mode = 'none')
#self.plot2 = self.scene.mlab.points3d(z, x, y, color = (0, 0, 1))
#on_trait_change('x1,z1')
def update_plot(self):
x = [1,2,3,4,self.x1,1,2,3,4,self.x1,1,2,3,4,self.x1,1,2,3,4,self.x1,1,2,3,4,self.x1]
z = [1,1,1,1,self.z1,1,1,1,1,self.z1,1,1,1,1,self.z1,1,1,1,1,self.z1,1,1,1,1,self.z1]
luc_func = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,self.z1]
self.plot.mlab_source.reset(x = x, z = z, luc_func = luc_func)
#self.plot2.mlab_source.set(y = y, z = z)
# the layout of the dialog created
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
HGroup(
'_', 'x1', "z1",
),
)
visualization = Visualization()
visualization.configure_traits()
Thanks for your help!
I have noticed a bug in the interactivity of points3d very similar to what you are describing here. I don't know exactly what is the origin of this bug but I regularly use the following workaround. The basic idea is to avoid mlab.points3d and instead call mlab.pipeline.glyph directly, as in:
def virtual_points3d(coords, figure=None, scale_factor=None, color=None,
name=None):
c = np.array(coords)
source = mlab.pipeline.scalar_scatter( c[:,0], c[:,1], c[:,2],
figure=figure)
return mlab.pipeline.glyph( source, scale_mode='none',
scale_factor=scale_factor,
mode='sphere', figure=figure, color=color, name=name)
Later you can change the colors by referring to the vtk object directly, rather than the mayavi trait that isn't connected properly:
glyph = virtual_points3d(coords)
glyph.mlab_source.dataset.point_data.scalars = new_values

Nested for loop and 3D Plot within Class Object

i am sure this is an easy problem to deal with, but i cant figure it out. I created a Borehole Class and want to compute my pore pressure around each Borehole/Well. Along a single axis, my code looks like this:
from scipy.special import *
import matplotlib.pyplot as plt
import numpy as np
from math import *
## Globale Variablen ##
rhof = 1000 # Dichte Flüssigkeit [kg/m³]
lameu = 11.2*10**9 # Lamé-Parameter, undrained [GPa]
lame = 8.4*10**9 # Lamé-Parameter, drained [GPa]
pi # durch Pythonmodul "math" gegeben
alpha = 0.65 # Biot-Willis-Koeffizient
G = 8.4*10**9 # Schermodul [GPa]
k = 1.0e-15 # Permeabilität [m²] bzw. [Darcy]
eta = 0.001 # Viskosität des Fluids [Pa*s]
## Berechnung der Parameter ##
kappa = k/eta
c = ((kappa*(lameu-lame)*(lame+2*G))/((alpha**2)*(lameu+2*G)))
## Wertebereich ##
xmin = 0
xmax = 100
xsteps = 1.0
x = np.arange(xmin, xmax, xsteps)
## Class ##
class Bohrloch(object):
loch_zaehler = 0
def __init__(self, xlage, tstart, q): # Funktion, um BL zu erzeugen
self.xlage = xlage
#self.ylage = ylage # Lage der Bohrung
self.tstart = tstart # Start der Injektion/Produktion
self.q = q # Fluidmenge
## Druck ##
def getPressure(self, t): # gibt nach Zeit t die zugehörigen Druckwerte aus
if (t-self.tstart<0): # Fehlermeldung, falls Startpunkt nach t liegt
return ()
print "Startpunkt liegt außerhalb des Förderzeitraumes!"
else:
self.r = np.sqrt((x-self.xlage)**2)
self.P = (self.q/(rhof*4*pi*kappa))*(expn(1,self.r**2/(4*c*(t-self.tstart))))
#self.P[self.xlage] = 0 # gibt Bohrlochlage wieder
self.z = self.P/1e6
return self.z # Druckwerte in [MPa]
def pressureTable (self, t, xschritt): # erstellt Wertetabelle
self.getPressure(t)
for i in range (xmin, xmax, xschritt):
print i, " ", self.z[i]
t = 1000*24*3600
b1 = Bohrloch(50,0*24*3600,6.0/1000)
b1.pressureTable(t,1)
With this method i get my desired pressure table. Now i want to have a pressure table for x and y values, including an 3D Plot. This is my code so far:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from scipy.special import *
import matplotlib.pyplot as plt
import numpy as np
from math import *
## Globale Variablen ##
rhof = 1000 # Dichte Flüssigkeit [kg/m³]
lameu = 11.2*10**9 # Lamé-Parameter, undrained [GPa]
lame = 8.4*10**9 # Lamé-Parameter, drained [GPa]
pi # durch Pythonmodul "math" gegeben
alpha = 0.65 # Biot-Willis-Koeffizient
G = 8.4*10**9 # Schermodul [GPa]
k = 1.0e-15 # Permeabilität [m²] bzw. [Darcy]
eta = 0.001 # Viskosität des Fluids [Pa*s]
## Berechnung der Parameter ##
kappa = k/eta
c = ((kappa*(lameu-lame)*(lame+2*G))/((alpha**2)*(lameu+2*G)))
## Wertebereich ##
xmin = 0
xmax = 100
xsteps = 1.0
x = np.arange(xmin,xmax,xsteps)
ymin = 0
ymax = 100
ysteps = 1.0
y = np.arange(ymin,ymax,ysteps)
## Klassendefinition ##
class Bohrloch(object):
loch_zaehler = 0
def __init__(self, xlage, ylage, tstart, q): # Funktion, um BL zu erzeugen
self.xlage = xlage # x-Lage der Bohrung
self.ylage = ylage # y-Lage der Bohrung
self.tstart = tstart # Start der Injektion/Produktion
self.q = q # Fluidmenge
## Druck ##
def getPressure(self, t):
if (t-self.tstart<0):
return ()
print "Startpunkt liegt außerhalb des Förderzeitraumes!"
else:
self.r = np.sqrt((x-self.xlage)**2+(y-self.ylage)**2)
self.P = (self.q/(rhof*4*pi*kappa))*(expn(1,self.r**2/(4*c*(t-self.tstart))))
self.P[self.xlage] = np.nan
self.P[self.ylage] = np.nan
self.z = self.P/1e6
return self.z # Druckwerte in [MPa]
def pressureTable (self, t, xschritt, yschritt):
self.getPressure(t)
for k in range (xmin, xmax, xschritt):
for l in range (ymin, ymax, yschritt):
# my mistake should be here?
print k, " ", l, " ", self.z[k][l]
def pressurePlot3D (self, t):
self.getPressure(t)
Z = self.z
X, Y = np.meshgrid(x,y)
Z[Z == np.inf] = np.nan
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet, linewidth=0,
antialiased=False, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
fig.colorbar(surf, shrink=0.5, aspect=5)
ax.set_xlim(xmin,xmax) # x-Achsenskala vorgeben
ax.set_ylim(ymin,ymax) # y-Achsenskala vorgeben
ax.set_title('Druckverteilung')
ax.set_xlabel('x-Richtung [m]')
ax.set_ylabel('y-Richtung Well [m]')
ax.set_zlabel('Druck in [MPa]')
plt.show()
t = 1000*24*3600
b1 = Bohrloch(50,50,0*24*3600,6.0/1000)
b1.pressureTable(t,1)
b1.pressurePlot3D(t)
Unfortunately, my table doesnt work and the desired 3D Plot looks strange. I am still a total beginner in Python and need some advices.
Can anyone help?
The problem is that self.z is not a two-dimensional array/list. Therefore, trying to access self.z[k][l] results in IndexError: invalid index to scalar variable.
I do not quite understand how you want to implement the second dimension. You introduce the y-position, but then, you just calculate a 1D radius array by using both the x- and y-location in
self.r = np.sqrt((x-self.xlage)**2+(y-self.ylage)**2)
The next question is, what do you intend with:
self.P[self.xlage] = np.nan
self.P[self.ylage] = np.nan
If you change xsteps and ysteps to 10, and call:
b1 = Bohrloch(2,3,0*24*3600,6.0/1000)
print b1.getPressure(t)
Your output will be:
[ 5.44152501 4.40905986 nan nan 2.87481753 2.64950827
2.46756653 2.31503845 2.18379093 2.06866598]
Why would you want to replace the 3rd and 4th elements with nan?
These issues are also at the basis of your plotting routine. Because you now have np.nan values in your array, these won't show in the plot. Because self.z is not two-dimensional, you are probably not getting the surface you may be expecting:
Here's a simple way of coming up with a 2D implementation. I am not familiar enough with what you are trying to do, but it gets the idea across:
def getPressure(self, t):
if (t-self.tstart<0):
return ()
print "Startpunkt liegt außerhalb des Förderzeitraumes!"
else:
# you need to initialize r, P and z as list of lists
# make this dependent on your x coordinates
# the second dimension will grow dynamically
self.r = [[] for ri in range(len(x))]
self.P = [[] for ri in range(len(x))]
self.z = [[] for ri in range(len(x))]
# iterate through both x and y independently
for ii in range(len(x)):
for jj in range(len(y)):
# append to the list that corresponds to the current x -value
# also, use x[ii] and y[jj] to call one x-, y-value at a time
self.r[ii].append(np.sqrt((x[ii]-self.xlage)**2+(y[jj]-self.ylage)**2))
# calling r[ii][-1] ensures you are using the value that was last added to the list:
self.P[ii].append((self.q/(rhof*4*pi*kappa))*(expn(1,self.r[ii][-1]**2/(4*c*(t-self.tstart)))))
self.z[ii].append(self.P[ii][-1]/1e6)
# now, you can use xlage and ylage to blank one value
# do this for both P and z, because z is now calculated inside the loop
self.P[self.xlage][self.ylage] = np.nan
self.z[self.xlage][self.ylage] = np.nan
return self.z
From your plotting routine, remove this line: Z[Z == np.inf] = np.nan, use your original command:
b1 = Bohrloch(50,50,0*24*3600,6.0/1000)
b1.pressurePlot3D(t)
and you will now get this plot:

Categories