I want to make a 2D contour plot using one SkyCoord object containing an array of coordinates as an input parameter.
To do this, I wanted to make a mesh gird over parameters.
The code is something like this.
l = np.linspace(0, 360, 180)
b = np.linspace(-90, 90, 90) # Two axes I wanted to make contour on.
y=y.reshape(y.size,1,1) #(originally) an 1D array the same size as `coords`.
l=l.reshape(1,l.size,1)
b=b.reshape(1,1,b.size)
coords = coords.reshape(y.shape) # No, this does not work.
coords.shape = y.shape # You can't write attributes like this. How frustrating.
z = Something_Fun((l,b),y,coords)
The problem comes here.
I tried to use np.meshgird over coords, but it returns a np.array of SkyCoord, rather than one SkyCoord object containing an array of coordinates, which is not what I want. For the function Something_Fun calls member functions of SkyCoord, which certainly does not work with a np.array.
Unfortunately, a built-in reshape method is not provided for SkyCoord, even though it does have a shape method! If keep the shape of coords, the code won't work because operations cannot broadcast with arrays of different dimensions.
Is there any elegant way to do this? I do not wish to rewrite codes that generates coords or the function Something_Fun because it would mess up many other things.
Exporting SkyCoord data to string and import again might do the trick, but is much too "dirty" and loses precision. I might try it as a last resort.
Ok, I've come up with an solution on my own. It still involves exporting and import back and forth, but it would not lose precision. And it just works.
coords=SkyCoord(coords.ra.reshape(y.shape),coords.dec.reshape(y.shape))
Wish they would provide an built-in reshape method in the future, which would save me some time~
Related
I have 3-dimensional DataArray (using xarray). I would like to apply a 1-dimensional to it along a certain dimension. Specifically, I want to apply the scipy.signal.medfilt() function but, again, it should be 1-dimensional.
So far I've successfully implemented this the following way:
for sample in data_raw.coords["sample"]:
for experiment in data_raw.coords["experiment"]:
data_filtered.loc[sample,experiment,:] = signal.medfilt(data_raw.loc[sample,experiment,:], 15)
(My data array has dimensions "sample", "experiment" and "wave_number. This code applies the filter along the "wave_number" dimension)
The problem with this is that it takes rather long to calculate and my intuition tells me that looping though coordinates like this is an inefficient way to do it. So I'm thinking about using the xarray.apply_ufunc() function, especially since I've used it in a similar fashion in the same code:
xr.apply_ufunc(np.linalg.norm, data, kwargs={"axis": 2}, input_core_dims=[["wave_number"]])
(This calculates the length of the vector along the "wave_number" dimension.)
I originally also had this loop through the coordinates just like the first code here.
The problem is when I try
xr.apply_ufunc(signal.medfilt, data_smooth, kwargs={"kernel_size": 15})
it returns a data array full of zeroes, presumably because it applies a 3D median filter and the data array contains NaN entries. I realize that the problem here is that I need to feed the scipy.signal.medfilt() function a 1D array but unfortunately there is no way to specify an axis along which to apply the filter (unlike numpy.linalg.norm()).
SO, how do I apply a 1D median filter without looping through coordinates?
If I understood correctly, you should use it like this:
xr.apply_ufunc(signal.medfilt, data_smooth, kwargs={"kernel_size": 15}, input_core_dims = [['wave_number']], vectorize=True)
with vectorize = True you vectorize your input function to be applied to slices of your array defined to preserve the core dimensions.
Nonetheless, as stated in the documentation:
This option exists for convenience, but is almost always slower than supplying a pre-vectorized function
because the implementation is essentially a for loop. However I still got faster results than by making my own loops.
I am having a bit of misunderstanding with numpy array
I have a set of two data (m, error) which I would like to plot
I save them in the array like this as I catch them in the same loop (which is probably causing the issue)
sum_error = np.append(m,error)
Then just simply trying to plot like this but it doesn't work as apparently this array is only of size 1 (with a tuple?)
plt.scatter(x=sum_error[:, 0], y=sum_error[:, 1])
What is the correct way to proceed? should I really make two different arrays, one for m, one for error in order to plot them?
Thanks
As it is answered on this thread, try using
np.vstack((m,error))
I have a function that I want to have quickly access the first (aka zeroth) element of a given Numpy array, which itself might have any number of dimensions. What's the quickest way to do that?
I'm currently using the following:
a.reshape(-1)[0]
This reshapes the perhaps-multi-dimensionsal array into a 1D array and grabs the zeroth element, which is short, sweet and often fast. However, I think this would work poorly with some arrays, e.g., an array that is a transposed view of a large array, as I worry this would end up needing to create a copy rather than just another view of the original array, in order to get everything in the right order. (Is that right? Or am I worrying needlessly?) Regardless, it feels like this is doing more work than what I really need, so I imagine some of you may know a generally faster way of doing this?
Other options I've considered are creating an iterator over the whole array and drawing just one element from it, or creating a vector of zeroes containing one zero for each dimension and using that to fancy-index into the array. But neither of these seems all that great either.
a.flat[0]
This should be pretty fast and never require a copy. (Note that a.flat is an instance of numpy.flatiter, not an array, which is why this operation can be done without a copy.)
You can use a.item(0); see the documentation at numpy.ndarray.item.
A possible disadvantage of this approach is that the return value is a Python data type, not a numpy object. For example, if a has data type numpy.uint8, a.item(0) will be a Python integer. If that is a problem, a.flat[0] is better--see #user2357112's answer.
np.hsplit(x, 2)[0]
Source: https://numpy.org/doc/stable/reference/generated/numpy.dsplit.html
Source:
https://numpy.org/doc/stable/reference/generated/numpy.hsplit.html
## y -- numpy array of shape (1, Ty)
if you want to get the first element:
use y.shape[0]
if you want to get the second element:
use y.shape[1]
Source:
https://docs.scipy.org/doc/numpy/reference/generated/numpy.take.html
You can also use the take for more complicated extraction (to get few elements):
numpy.take(a, indices, axis=None, out=None, mode='raise')[source] Take
elements from an array along an axis.
is it possible to concatenate two (or more) meshes?
Example:
import fipy
meshA = fipy.Grid2D(nx=5, ny=3)
meshB = fipy.Grid2D(nx=5, ny=6)
mesh = fipy.vstack(meshA, meshB)
Same goes for 1D, or 2D grids.
Intermediate Question: Is it possible to define an offset?
Absolutely, and you actually have to do the second to do the first:
mesh = meshA + (meshB + [[0], [3]])
which displaces meshB upwards by 3 units and then concatenates it to meshA.
This is covered in the docstring for Mesh.__add__, but the Sphinx documentation tool unfortunately doesn't include that in the output. We'll need to explicitly put this in the documentation where it can be read.
Note that the resulting mesh is no longer a Grid and so loses some efficiencies. For this simple case, you're obviously better off just setting ny=9. For a bit more complicated case, you might want to do:
mesh = fipy.Grid2D(nx=5, dy=[1,1,1,.5,.5,.5,.5,.5,.5])
if the reason you're grafting meshes is to change the resolution.
I've got the following routine I've written that takes two arbitrary curves and warps the space between them so it fits between two straight lines. For the loop, it process it per column as np.linspace doesn't operate on vectors AFAIK. Is there way to get rid of this loop and hit the whole thing at once?
def warp(img, iris_curve, pupil_curve):
height, width = img.shape[:2]
iris_height = np.uint8(np.max(np.int8(iris_curve) - pupil_curve))
out = np.zeros((iris_height, width))
for r in range(0,width):
map_theta = np.linspace(pupil_curve[r], iris_curve[r], iris_height)
map_theta = np.uint8(np.rint(map_theta))
out[:, r] = img[map_theta, r]
return np.uint8(out)
Thanks!
If you peek into the source code of np.linspace, you can use that as a guide to vectorize your code. Your loop would then be replaced by something like:
steps = (iris_curve - pupil_curve) / iris_height
map_theta = np.arange(iris_height)[:, None] * steps + pupil_curve
map_theta = np.rint(map_theta).astype(np.uint8)
out = img[map_theta, np.arange(width)]
You may have to transpose the output, it's hard to debug this kind of code without an example.
My first thoughts looking at this code is that the for loop is unlikely to be the most significant thing hampering performace. There is an awful lot of copying of data around in this code (calling linspace creates a new array then this is copied back into the larger output array. casting to different types also involves copying data around). For example, can you not initiate your output as
np.empty((h,w),dtype=np.uint8)
Moreover do you really need to explicitly calculate all these values? Unless you reference all of them you might be better off just using the 2D linear interpolator from scipy.
If you really want to produce the output as-is I think you'll have to write something custom in Cython or similar.