def show(self, title=None, method='scatter', force_show=False, fig=None, **kwargs): """Display this vector graphically. Parameters ---------- title : string, optional Set the title of the figure method : string, optional The following plotting methods are available: 'scatter' : point plot 'plot' : graph plot force_show : bool, optional Whether the plot should be forced to be shown now or deferred until later. Note that some backends always displays the plot, regardless of this value. fig : `matplotlib.figure.Figure`, optional Figure to draw into. Expected to be of same "style" as the figure given by this function. The most common use case is that ``fig`` is the return value of an earlier call to this function. kwargs : {'figsize', 'saveto', ...}, optional Extra keyword arguments passed on to the display method. See the Matplotlib functions for documentation of extra options. Returns ------- fig : `matplotlib.figure.Figure` Resulting figure. If ``fig`` was given, the returned object is a reference to it. See Also -------- odl.util.graphics.show_discrete_data : Underlying implementation """ from odl.util.graphics import show_discrete_data from odl.discr import uniform_grid grid = uniform_grid(0, self.size - 1, self.size) return show_discrete_data(self.asarray(), grid, title=title, method=method, force_show=force_show, fig=fig, **kwargs)
def show(self, title=None, method='', indices=None, force_show=False, fig=None, **kwargs): """Display the function graphically. Parameters ---------- title : string, optional Set the title of the figure method : string, optional 1d methods: ``'plot'`` : graph plot ``'scatter'`` : scattered 2d points (2nd axis <-> value) 2d methods: ``'imshow'`` : image plot with coloring according to value, including a colorbar. ``'scatter'`` : cloud of scattered 3d points (3rd axis <-> value) indices : index expression, optional Display a slice of the array instead of the full array. The index expression is most easily created with the `numpy.s_` constructor, i.e. supply ``np.s_[:, 1, :]`` to display the first slice along the second axis. For data with 3 or more dimensions, the 2d slice in the first two axes at the "middle" along the remaining axes is shown (semantically ``[:, :, shape[2:] // 2]``). This option is mutually exclusive to ``coords``. force_show : bool, optional Whether the plot should be forced to be shown now or deferred until later. Note that some backends always displays the plot, regardless of this value. fig : `matplotlib.figure.Figure`, optional The figure to show in. Expected to be of same "style", as the figure given by this function. The most common use case is that ``fig`` is the return value of an earlier call to this function. kwargs : {'figsize', 'saveto', 'clim', ...}, optional Extra keyword arguments passed on to the display method. See the Matplotlib functions for documentation of extra options. Returns ------- fig : `matplotlib.figure.Figure` The resulting figure. It is also shown to the user. See Also -------- odl.util.graphics.show_discrete_data : Underlying implementation """ from odl.discr import uniform_grid from odl.util.graphics import show_discrete_data # Default to showing x-y slice "in the middle" if indices is None and self.ndim >= 3: indices = tuple([slice(None)] * 2 + [n // 2 for n in self.space.shape[2:]]) if isinstance(indices, (Integral, slice)): indices = (indices, ) elif indices is None or indices == Ellipsis: indices = (slice(None), ) * self.ndim else: indices = tuple(indices) # Replace None by slice(None) indices = tuple(slice(None) if idx is None else idx for idx in indices) if Ellipsis in indices: # Replace Ellipsis with the correct number of [:] expressions pos = indices.index(Ellipsis) indices = (indices[:pos] + (np.s_[:], ) * (self.ndim - len(indices) + 1) + indices[pos + 1:]) if len(indices) < self.ndim: raise ValueError('too few axes ({} < {})'.format( len(indices), self.ndim)) if len(indices) > self.ndim: raise ValueError('too many axes ({} > {})'.format( len(indices), self.ndim)) # Squeeze grid and values according to the index expression full_grid = uniform_grid([0] * self.ndim, np.array(self.shape) - 1, self.shape) grid = full_grid[indices].squeeze() values = self.asarray()[indices].squeeze() return show_discrete_data(values, grid, title=title, method=method, force_show=force_show, fig=fig, **kwargs)
def reciprocal_grid(grid, shift=True, axes=None, halfcomplex=False): """Return the reciprocal of the given regular grid. This function calculates the reciprocal (Fourier/frequency space) grid for a given regular grid defined by the nodes:: x[k] = x[0] + k * s, where ``k = (k[0], ..., k[d-1])`` is a ``d``-dimensional index in the range ``0 <= k < N`` (component-wise). The multi-index ``N`` is the shape of the input grid. This grid's reciprocal is then given by the nodes:: xi[j] = xi[0] + j * sigma, with the reciprocal grid stride ``sigma = 2*pi / (s * N)``. The minimum frequency ``xi[0]`` can in principle be chosen freely, but usually it is chosen in a such a way that the reciprocal grid is centered around zero. For this, there are two possibilities: 1. Make the grid point-symmetric around 0. 2. Make the grid "almost" point-symmetric around zero by shifting it to the left by half a reciprocal stride. In the first case, the minimum frequency (per axis) is given as:: xi_1[0] = -pi/s + pi/(s*n) = -pi/s + sigma/2. For the second case, it is:: xi_1[0] = -pi / s. Note that the zero frequency is contained in case 1 for an odd number of points, while for an even size, the second option guarantees that 0 is contained. If a real-to-complex (half-complex) transform is to be computed, the reciprocal grid has the shape ``M[i] = floor(N[i]/2) + 1`` in the last transform axis ``i``. Parameters ---------- grid : uniform `RectGrid` Original sampling grid,. shift : bool or sequence of bools, optional If ``True``, the grid is shifted by half a stride in the negative direction. With a sequence, this option is applied separately on each axis. axes : int or sequence of ints, optional Dimensions in which to calculate the reciprocal. The sequence must have the same length as ``shift`` if the latter is given as a sequence. ``None`` means all axes in ``grid``. halfcomplex : bool, optional If ``True``, return the half of the grid with last coordinate less than zero. This is related to the fact that for real-valued functions, the other half is the mirrored complex conjugate of the given half and therefore needs not be stored. Returns ------- reciprocal_grid : uniform `RectGrid` The reciprocal grid. """ if axes is None: axes = list(range(grid.ndim)) else: try: axes = [int(axes)] except TypeError: axes = list(axes) # List indicating shift or not per "active" axis, same length as axes shift_list = normalized_scalar_param_list(shift, length=len(axes), param_conv=bool) # Full-length vectors stride = grid.stride shape = np.array(grid.shape) rmin = grid.min_pt.copy() rmax = grid.max_pt.copy() rshape = list(shape) # Shifted axes (full length to avoid ugly double indexing) shifted = np.zeros(grid.ndim, dtype=bool) shifted[axes] = shift_list rmin[shifted] = -np.pi / stride[shifted] # Length min->max increases by double the shift, so we # have to compensate by a full stride rmax[shifted] = (-rmin[shifted] - 2 * np.pi / (stride[shifted] * shape[shifted])) # Non-shifted axes not_shifted = np.zeros(grid.ndim, dtype=bool) not_shifted[axes] = np.logical_not(shift_list) rmin[not_shifted] = ((-1.0 + 1.0 / shape[not_shifted]) * np.pi / stride[not_shifted]) rmax[not_shifted] = -rmin[not_shifted] # Change last axis shape and max if halfcomplex if halfcomplex: rshape[axes[-1]] = shape[axes[-1]] // 2 + 1 # - Odd and shifted: - stride / 2 # - Even and not shifted: + stride / 2 # - Otherwise: 0 last_odd = shape[axes[-1]] % 2 == 1 last_shifted = shift_list[-1] half_rstride = np.pi / (shape[axes[-1]] * stride[axes[-1]]) if last_odd and last_shifted: rmax[axes[-1]] = -half_rstride elif not last_odd and not last_shifted: rmax[axes[-1]] = half_rstride else: rmax[axes[-1]] = 0 return uniform_grid(rmin, rmax, rshape)
def realspace_grid(recip_grid, x0, axes=None, halfcomplex=False, halfcx_parity='even'): """Return the real space grid from the given reciprocal grid. Given a reciprocal grid:: xi[j] = xi[0] + j * sigma, with a multi-index ``j = (j[0], ..., j[d-1])`` in the range ``0 <= j < M``, this function calculates the original grid:: x[k] = x[0] + k * s by using a provided ``x[0]`` and calculating the stride ``s``. If the reciprocal grid is interpreted as coming from a usual complex-to-complex FFT, it is ``N == M``, and the stride is:: s = 2*pi / (sigma * N) For a reciprocal grid from a real-to-complex (half-complex) FFT, it is ``M[i] = floor(N[i]/2) + 1`` in the last transform axis ``i``. To resolve the ambiguity regarding the parity of ``N[i]``, the it must be specified if the output shape should be even or odd, resulting in:: odd : N[i] = 2 * M[i] - 1 even: N[i] = 2 * M[i] - 2 The output stride is calculated with this ``N`` as above in this case. Parameters ---------- recip_grid : uniform `RectGrid` Sampling grid in reciprocal space. x0 : `array-like` Desired minimum point of the real space grid. axes : int or sequence of ints, optional Dimensions in which to calculate the real space grid. The sequence must have the same length as ``shift`` if the latter is given as a sequence. ``None`` means "all axes". halfcomplex : bool, optional If ``True``, interpret the given grid as the reciprocal as used in a half-complex FFT (see above). Otherwise, the grid is regarded as being used in a complex-to-complex transform. halfcx_parity : {'even', 'odd'} Use this parity for the shape of the returned grid in the last axis of ``axes`` in the case ``halfcomplex=True`` Returns ------- irecip : uniform `RectGrid` The inverse reciprocal grid. """ if axes is None: axes = list(range(recip_grid.ndim)) else: try: axes = [int(axes)] except TypeError: axes = list(axes) rstride = recip_grid.stride rshape = recip_grid.shape # Calculate shape of the output grid by adjusting in axes[-1] irshape = list(rshape) if halfcomplex: if str(halfcx_parity).lower() == 'even': irshape[axes[-1]] = 2 * rshape[axes[-1]] - 2 elif str(halfcx_parity).lower() == 'odd': irshape[axes[-1]] = 2 * rshape[axes[-1]] - 1 else: raise ValueError("`halfcomplex` parity '{}' not understood" "".format(halfcx_parity)) irmin = np.asarray(x0) irshape = np.asarray(irshape) irstride = np.copy(rstride) irstride[axes] = 2 * np.pi / (irshape[axes] * rstride[axes]) irmax = irmin + (irshape - 1) * irstride return uniform_grid(irmin, irmax, irshape)