We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
remove_nans_1D fails for list
```
>>> wt.kit.remove_nans_1D([np.nan, 1, 2, 2])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    wt.kit.remove_nans_1D([np.nan, 1, 2, 2])
  File "/home/kyle/wright/WrightTools/WrightTools/kit/_array.py", line 223, in rem
ove_nans_1D
    return tuple(a[goods] for a in args)
  File "/home/kyle/wright/WrightTools/WrightTools/kit/_array.py", line 223, in <ge
nexpr>
    return tuple(a[goods] for a in args)
TypeError: list indices must be integers or slices, not list
>>> wt.kit.remove_nans_1D(np.array([np.nan, 1, 2, 2]))
(array([1., 2., 2.]),)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `WrightTools/kit/_array.py`
Content:
```
1 """Array interaction tools."""
2 
3 
4 # --- import --------------------------------------------------------------------------------------
5 
6 
7 import numpy as np
8 
9 from .. import exceptions as wt_exceptions
10 
11 
12 # --- define --------------------------------------------------------------------------------------
13 
14 
15 __all__ = ['closest_pair',
16            'diff',
17            'fft',
18            'joint_shape',
19            'orthogonal',
20            'remove_nans_1D',
21            'share_nans',
22            'smooth_1D',
23            'unique',
24            'valid_index']
25 
26 
27 # --- functions -----------------------------------------------------------------------------------
28 
29 
30 def closest_pair(arr, give='indicies'):
31     """Find the pair of indices corresponding to the closest elements in an array.
32 
33     If multiple pairs are equally close, both pairs of indicies are returned.
34     Optionally returns the closest distance itself.
35 
36     I am sure that this could be written as a cheaper operation. I
37     wrote this as a quick and dirty method because I need it now to use on some
38     relatively small arrays. Feel free to refactor if you need this operation
39     done as fast as possible. - Blaise 2016-02-07
40 
41     Parameters
42     ----------
43     arr : numpy.ndarray
44         The array to search.
45     give : {'indicies', 'distance'} (optional)
46         Toggle return behavior. If 'distance', returns a single float - the
47         closest distance itself. Default is indicies.
48 
49     Returns
50     -------
51     list of lists of two tuples
52         List containing lists of two tuples: indicies the nearest pair in the
53         array.
54 
55         >>> arr = np.array([0, 1, 2, 3, 3, 4, 5, 6, 1])
56         >>> closest_pair(arr)
57         [[(1,), (8,)], [(3,), (4,)]]
58 
59     """
60     idxs = [idx for idx in np.ndindex(arr.shape)]
61     outs = []
62     min_dist = arr.max() - arr.min()
63     for idxa in idxs:
64         for idxb in idxs:
65             if idxa == idxb:
66                 continue
67             dist = abs(arr[idxa] - arr[idxb])
68             if dist == min_dist:
69                 if not [idxb, idxa] in outs:
70                     outs.append([idxa, idxb])
71             elif dist < min_dist:
72                 min_dist = dist
73                 outs = [[idxa, idxb]]
74     if give == 'indicies':
75         return outs
76     elif give == 'distance':
77         return min_dist
78     else:
79         raise KeyError('give not recognized in closest_pair')
80 
81 
82 def diff(xi, yi, order=1):
83     """Take the numerical derivative of a 1D array.
84 
85     Output is mapped onto the original coordinates  using linear interpolation.
86     Expects monotonic xi values.
87 
88     Parameters
89     ----------
90     xi : 1D array-like
91         Coordinates.
92     yi : 1D array-like
93         Values.
94     order : positive integer (optional)
95         Order of differentiation.
96 
97     Returns
98     -------
99     1D numpy array
100         Numerical derivative. Has the same shape as the input arrays.
101     """
102     yi = np.array(yi).copy()
103     flip = False
104     if xi[-1] < xi[0]:
105         xi = np.flipud(xi.copy())
106         yi = np.flipud(yi)
107         flip = True
108     midpoints = (xi[1:] + xi[:-1]) / 2
109     for _ in range(order):
110         d = np.diff(yi)
111         d /= np.diff(xi)
112         yi = np.interp(xi, midpoints, d)
113     if flip:
114         yi = np.flipud(yi)
115     return yi
116 
117 
118 def fft(xi, yi, axis=0):
119     """Take the 1D FFT of an N-dimensional array and return "sensible" properly shifted arrays.
120 
121     Parameters
122     ----------
123     xi : numpy.ndarray
124         1D array over which the points to be FFT'ed are defined
125     yi : numpy.ndarray
126         ND array with values to FFT
127     axis : int
128         axis of yi to perform FFT over
129 
130     Returns
131     -------
132     xi : 1D numpy.ndarray
133         1D array. Conjugate to input xi. Example: if input xi is in the time
134         domain, output xi is in frequency domain.
135     yi : ND numpy.ndarray
136         FFT. Has the same shape as the input array (yi).
137     """
138     # xi must be 1D
139     if xi.ndim != 1:
140         raise wt_exceptions.DimensionalityError(1, xi.ndim)
141     # xi must be evenly spaced
142     spacing = np.diff(xi)
143     if not np.allclose(spacing, spacing.mean()):
144         raise RuntimeError('WrightTools.kit.fft: argument xi must be evenly spaced')
145     # fft
146     yi = np.fft.fft(yi, axis=axis)
147     d = (xi.max() - xi.min()) / (xi.size - 1)
148     xi = np.fft.fftfreq(xi.size, d=d)
149     # shift
150     xi = np.fft.fftshift(xi)
151     yi = np.fft.fftshift(yi, axes=axis)
152     return xi, yi
153 
154 
155 def joint_shape(*args):
156     """Given a set of arrays, return the joint shape.
157 
158     Parameters
159     ----------
160     args : array-likes
161 
162     Returns
163     -------
164     tuple of int
165         Joint shape.
166     """
167     if len(args) == 0:
168         return ()
169     shape = []
170     shapes = [a.shape for a in args]
171     ndim = args[0].ndim
172     for i in range(ndim):
173         shape.append(max([s[i] for s in shapes]))
174     return tuple(shape)
175 
176 
177 def orthogonal(*args):
178     """Determine if a set of arrays are orthogonal.
179 
180     Parameters
181     ----------
182     args : array-likes or array shapes
183 
184     Returns
185     -------
186     bool
187         Array orthogonality condition.
188     """
189     for i, arg in enumerate(args):
190         if hasattr(arg, 'shape'):
191             args[i] = arg.shape
192     for s in zip(*args):
193         if np.product(s) != max(s):
194             return False
195     return True
196 
197 
198 def remove_nans_1D(*args):
199     """Remove nans in a set of 1D arrays.
200 
201     Removes indicies in all arrays if any array is nan at that index.
202     All input arrays must have the same size.
203 
204     Parameters
205     ----------
206     args : 1D arrays
207 
208     Returns
209     -------
210     tuple
211         Tuple of 1D arrays in same order as given, with nan indicies removed.
212     """
213     # find all indicies to keep
214     bads = np.array([])
215     for arr in args:
216         bad = np.array(np.where(np.isnan(arr))).flatten()
217         bads = np.hstack((bad, bads))
218     if hasattr(args, 'shape') and len(args.shape) == 1:
219         goods = [i for i in np.arange(args.shape[0]) if i not in bads]
220     else:
221         goods = [i for i in np.arange(len(args[0])) if i not in bads]
222     # apply
223     return tuple(a[goods] for a in args)
224 
225 
226 def share_nans(*arrs):
227     """Take a list of nD arrays and return a new list of nD arrays.
228 
229     The new list is in the same order as the old list.
230     If one indexed element in an old array is nan then every element for that
231     index in all new arrays in the list is then nan.
232 
233     Parameters
234     ----------
235     *arrs : nD arrays.
236 
237     Returns
238     -------
239     list
240         List of nD arrays in same order as given, with nan indicies syncronized.
241     """
242     nans = np.zeros((arrs[0].shape))
243     for arr in arrs:
244         nans *= arr
245     return tuple([a + nans for a in arrs])
246 
247 
248 def smooth_1D(arr, n=10):
249     """Smooth 1D data by 'running average'.
250 
251     Parameters
252     ----------
253     n : int
254         number of points to average
255     """
256     for i in range(n, len(arr) - n):
257         window = arr[i - n:i + n].copy()
258         arr[i] = window.mean()
259     return arr
260 
261 
262 def unique(arr, tolerance=1e-6):
263     """Return unique elements in 1D array, within tolerance.
264 
265     Parameters
266     ----------
267     arr : array_like
268         Input array. This will be flattened if it is not already 1D.
269     tolerance : number (optional)
270         The tolerance for uniqueness.
271 
272     Returns
273     -------
274     array
275         The sorted unique values.
276     """
277     arr = sorted(arr.flatten())
278     unique = []
279     while len(arr) > 0:
280         current = arr[0]
281         lis = [xi for xi in arr if np.abs(current - xi) < tolerance]
282         arr = [xi for xi in arr if not np.abs(lis[0] - xi) < tolerance]
283         xi_lis_average = sum(lis) / len(lis)
284         unique.append(xi_lis_average)
285     return np.array(unique)
286 
287 
288 def valid_index(index, shape):
289     """Get a valid index for a broadcastable shape.
290 
291     Parameters
292     ----------
293     index : tuple
294         Given index.
295     shape : tuple of int
296         Shape.
297 
298     Returns
299     -------
300     tuple
301         Valid index.
302     """
303     # append slices to index
304     index = list(index)
305     while len(index) < len(shape):
306         index.append(slice(None))
307     # fill out, in reverse
308     out = []
309     for i, s in zip(index[::-1], shape[::-1]):
310         if s == 1:
311             if isinstance(i, slice):
312                 out.append(slice(None))
313             else:
314                 out.append(0)
315         else:
316             out.append(i)
317     return tuple(out[::-1])
318
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/WrightTools/kit/_array.py b/WrightTools/kit/_array.py
--- a/WrightTools/kit/_array.py
+++ b/WrightTools/kit/_array.py
@@ -210,17 +210,10 @@
     tuple
         Tuple of 1D arrays in same order as given, with nan indicies removed.
     """
-    # find all indicies to keep
-    bads = np.array([])
-    for arr in args:
-        bad = np.array(np.where(np.isnan(arr))).flatten()
-        bads = np.hstack((bad, bads))
-    if hasattr(args, 'shape') and len(args.shape) == 1:
-        goods = [i for i in np.arange(args.shape[0]) if i not in bads]
-    else:
-        goods = [i for i in np.arange(len(args[0])) if i not in bads]
-    # apply
-    return tuple(a[goods] for a in args)
+    vals = np.isnan(args[0])
+    for a in args:
+        vals |= np.isnan(a)
+    return tuple(np.array(a)[vals == False] for a in args)
 
 
 def share_nans(*arrs):

{"golden_diff": "diff --git a/WrightTools/kit/_array.py b/WrightTools/kit/_array.py\n--- a/WrightTools/kit/_array.py\n+++ b/WrightTools/kit/_array.py\n@@ -210,17 +210,10 @@\n     tuple\n         Tuple of 1D arrays in same order as given, with nan indicies removed.\n     \"\"\"\n-    # find all indicies to keep\n-    bads = np.array([])\n-    for arr in args:\n-        bad = np.array(np.where(np.isnan(arr))).flatten()\n-        bads = np.hstack((bad, bads))\n-    if hasattr(args, 'shape') and len(args.shape) == 1:\n-        goods = [i for i in np.arange(args.shape[0]) if i not in bads]\n-    else:\n-        goods = [i for i in np.arange(len(args[0])) if i not in bads]\n-    # apply\n-    return tuple(a[goods] for a in args)\n+    vals = np.isnan(args[0])\n+    for a in args:\n+        vals |= np.isnan(a)\n+    return tuple(np.array(a)[vals == False] for a in args)\n \n \n def share_nans(*arrs):\n", "issue": "remove_nans_1D fails for list\n```\r\n>>> wt.kit.remove_nans_1D([np.nan, 1, 2, 2])\r\nTraceback (most recent call last):\r\n  File \"<input>\", line 1, in <module>\r\n    wt.kit.remove_nans_1D([np.nan, 1, 2, 2])\r\n  File \"/home/kyle/wright/WrightTools/WrightTools/kit/_array.py\", line 223, in rem\r\nove_nans_1D\r\n    return tuple(a[goods] for a in args)\r\n  File \"/home/kyle/wright/WrightTools/WrightTools/kit/_array.py\", line 223, in <ge\r\nnexpr>\r\n    return tuple(a[goods] for a in args)\r\nTypeError: list indices must be integers or slices, not list\r\n>>> wt.kit.remove_nans_1D(np.array([np.nan, 1, 2, 2]))\r\n(array([1., 2., 2.]),)\r\n```\n", "before_files": [{"content": "\"\"\"Array interaction tools.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nimport numpy as np\n\nfrom .. import exceptions as wt_exceptions\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\n__all__ = ['closest_pair',\n           'diff',\n           'fft',\n           'joint_shape',\n           'orthogonal',\n           'remove_nans_1D',\n           'share_nans',\n           'smooth_1D',\n           'unique',\n           'valid_index']\n\n\n# --- functions -----------------------------------------------------------------------------------\n\n\ndef closest_pair(arr, give='indicies'):\n    \"\"\"Find the pair of indices corresponding to the closest elements in an array.\n\n    If multiple pairs are equally close, both pairs of indicies are returned.\n    Optionally returns the closest distance itself.\n\n    I am sure that this could be written as a cheaper operation. I\n    wrote this as a quick and dirty method because I need it now to use on some\n    relatively small arrays. Feel free to refactor if you need this operation\n    done as fast as possible. - Blaise 2016-02-07\n\n    Parameters\n    ----------\n    arr : numpy.ndarray\n        The array to search.\n    give : {'indicies', 'distance'} (optional)\n        Toggle return behavior. If 'distance', returns a single float - the\n        closest distance itself. Default is indicies.\n\n    Returns\n    -------\n    list of lists of two tuples\n        List containing lists of two tuples: indicies the nearest pair in the\n        array.\n\n        >>> arr = np.array([0, 1, 2, 3, 3, 4, 5, 6, 1])\n        >>> closest_pair(arr)\n        [[(1,), (8,)], [(3,), (4,)]]\n\n    \"\"\"\n    idxs = [idx for idx in np.ndindex(arr.shape)]\n    outs = []\n    min_dist = arr.max() - arr.min()\n    for idxa in idxs:\n        for idxb in idxs:\n            if idxa == idxb:\n                continue\n            dist = abs(arr[idxa] - arr[idxb])\n            if dist == min_dist:\n                if not [idxb, idxa] in outs:\n                    outs.append([idxa, idxb])\n            elif dist < min_dist:\n                min_dist = dist\n                outs = [[idxa, idxb]]\n    if give == 'indicies':\n        return outs\n    elif give == 'distance':\n        return min_dist\n    else:\n        raise KeyError('give not recognized in closest_pair')\n\n\ndef diff(xi, yi, order=1):\n    \"\"\"Take the numerical derivative of a 1D array.\n\n    Output is mapped onto the original coordinates  using linear interpolation.\n    Expects monotonic xi values.\n\n    Parameters\n    ----------\n    xi : 1D array-like\n        Coordinates.\n    yi : 1D array-like\n        Values.\n    order : positive integer (optional)\n        Order of differentiation.\n\n    Returns\n    -------\n    1D numpy array\n        Numerical derivative. Has the same shape as the input arrays.\n    \"\"\"\n    yi = np.array(yi).copy()\n    flip = False\n    if xi[-1] < xi[0]:\n        xi = np.flipud(xi.copy())\n        yi = np.flipud(yi)\n        flip = True\n    midpoints = (xi[1:] + xi[:-1]) / 2\n    for _ in range(order):\n        d = np.diff(yi)\n        d /= np.diff(xi)\n        yi = np.interp(xi, midpoints, d)\n    if flip:\n        yi = np.flipud(yi)\n    return yi\n\n\ndef fft(xi, yi, axis=0):\n    \"\"\"Take the 1D FFT of an N-dimensional array and return \"sensible\" properly shifted arrays.\n\n    Parameters\n    ----------\n    xi : numpy.ndarray\n        1D array over which the points to be FFT'ed are defined\n    yi : numpy.ndarray\n        ND array with values to FFT\n    axis : int\n        axis of yi to perform FFT over\n\n    Returns\n    -------\n    xi : 1D numpy.ndarray\n        1D array. Conjugate to input xi. Example: if input xi is in the time\n        domain, output xi is in frequency domain.\n    yi : ND numpy.ndarray\n        FFT. Has the same shape as the input array (yi).\n    \"\"\"\n    # xi must be 1D\n    if xi.ndim != 1:\n        raise wt_exceptions.DimensionalityError(1, xi.ndim)\n    # xi must be evenly spaced\n    spacing = np.diff(xi)\n    if not np.allclose(spacing, spacing.mean()):\n        raise RuntimeError('WrightTools.kit.fft: argument xi must be evenly spaced')\n    # fft\n    yi = np.fft.fft(yi, axis=axis)\n    d = (xi.max() - xi.min()) / (xi.size - 1)\n    xi = np.fft.fftfreq(xi.size, d=d)\n    # shift\n    xi = np.fft.fftshift(xi)\n    yi = np.fft.fftshift(yi, axes=axis)\n    return xi, yi\n\n\ndef joint_shape(*args):\n    \"\"\"Given a set of arrays, return the joint shape.\n\n    Parameters\n    ----------\n    args : array-likes\n\n    Returns\n    -------\n    tuple of int\n        Joint shape.\n    \"\"\"\n    if len(args) == 0:\n        return ()\n    shape = []\n    shapes = [a.shape for a in args]\n    ndim = args[0].ndim\n    for i in range(ndim):\n        shape.append(max([s[i] for s in shapes]))\n    return tuple(shape)\n\n\ndef orthogonal(*args):\n    \"\"\"Determine if a set of arrays are orthogonal.\n\n    Parameters\n    ----------\n    args : array-likes or array shapes\n\n    Returns\n    -------\n    bool\n        Array orthogonality condition.\n    \"\"\"\n    for i, arg in enumerate(args):\n        if hasattr(arg, 'shape'):\n            args[i] = arg.shape\n    for s in zip(*args):\n        if np.product(s) != max(s):\n            return False\n    return True\n\n\ndef remove_nans_1D(*args):\n    \"\"\"Remove nans in a set of 1D arrays.\n\n    Removes indicies in all arrays if any array is nan at that index.\n    All input arrays must have the same size.\n\n    Parameters\n    ----------\n    args : 1D arrays\n\n    Returns\n    -------\n    tuple\n        Tuple of 1D arrays in same order as given, with nan indicies removed.\n    \"\"\"\n    # find all indicies to keep\n    bads = np.array([])\n    for arr in args:\n        bad = np.array(np.where(np.isnan(arr))).flatten()\n        bads = np.hstack((bad, bads))\n    if hasattr(args, 'shape') and len(args.shape) == 1:\n        goods = [i for i in np.arange(args.shape[0]) if i not in bads]\n    else:\n        goods = [i for i in np.arange(len(args[0])) if i not in bads]\n    # apply\n    return tuple(a[goods] for a in args)\n\n\ndef share_nans(*arrs):\n    \"\"\"Take a list of nD arrays and return a new list of nD arrays.\n\n    The new list is in the same order as the old list.\n    If one indexed element in an old array is nan then every element for that\n    index in all new arrays in the list is then nan.\n\n    Parameters\n    ----------\n    *arrs : nD arrays.\n\n    Returns\n    -------\n    list\n        List of nD arrays in same order as given, with nan indicies syncronized.\n    \"\"\"\n    nans = np.zeros((arrs[0].shape))\n    for arr in arrs:\n        nans *= arr\n    return tuple([a + nans for a in arrs])\n\n\ndef smooth_1D(arr, n=10):\n    \"\"\"Smooth 1D data by 'running average'.\n\n    Parameters\n    ----------\n    n : int\n        number of points to average\n    \"\"\"\n    for i in range(n, len(arr) - n):\n        window = arr[i - n:i + n].copy()\n        arr[i] = window.mean()\n    return arr\n\n\ndef unique(arr, tolerance=1e-6):\n    \"\"\"Return unique elements in 1D array, within tolerance.\n\n    Parameters\n    ----------\n    arr : array_like\n        Input array. This will be flattened if it is not already 1D.\n    tolerance : number (optional)\n        The tolerance for uniqueness.\n\n    Returns\n    -------\n    array\n        The sorted unique values.\n    \"\"\"\n    arr = sorted(arr.flatten())\n    unique = []\n    while len(arr) > 0:\n        current = arr[0]\n        lis = [xi for xi in arr if np.abs(current - xi) < tolerance]\n        arr = [xi for xi in arr if not np.abs(lis[0] - xi) < tolerance]\n        xi_lis_average = sum(lis) / len(lis)\n        unique.append(xi_lis_average)\n    return np.array(unique)\n\n\ndef valid_index(index, shape):\n    \"\"\"Get a valid index for a broadcastable shape.\n\n    Parameters\n    ----------\n    index : tuple\n        Given index.\n    shape : tuple of int\n        Shape.\n\n    Returns\n    -------\n    tuple\n        Valid index.\n    \"\"\"\n    # append slices to index\n    index = list(index)\n    while len(index) < len(shape):\n        index.append(slice(None))\n    # fill out, in reverse\n    out = []\n    for i, s in zip(index[::-1], shape[::-1]):\n        if s == 1:\n            if isinstance(i, slice):\n                out.append(slice(None))\n            else:\n                out.append(0)\n        else:\n            out.append(i)\n    return tuple(out[::-1])\n", "path": "WrightTools/kit/_array.py"}], "after_files": [{"content": "\"\"\"Array interaction tools.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nimport numpy as np\n\nfrom .. import exceptions as wt_exceptions\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\n__all__ = ['closest_pair',\n           'diff',\n           'fft',\n           'joint_shape',\n           'orthogonal',\n           'remove_nans_1D',\n           'share_nans',\n           'smooth_1D',\n           'unique',\n           'valid_index']\n\n\n# --- functions -----------------------------------------------------------------------------------\n\n\ndef closest_pair(arr, give='indicies'):\n    \"\"\"Find the pair of indices corresponding to the closest elements in an array.\n\n    If multiple pairs are equally close, both pairs of indicies are returned.\n    Optionally returns the closest distance itself.\n\n    I am sure that this could be written as a cheaper operation. I\n    wrote this as a quick and dirty method because I need it now to use on some\n    relatively small arrays. Feel free to refactor if you need this operation\n    done as fast as possible. - Blaise 2016-02-07\n\n    Parameters\n    ----------\n    arr : numpy.ndarray\n        The array to search.\n    give : {'indicies', 'distance'} (optional)\n        Toggle return behavior. If 'distance', returns a single float - the\n        closest distance itself. Default is indicies.\n\n    Returns\n    -------\n    list of lists of two tuples\n        List containing lists of two tuples: indicies the nearest pair in the\n        array.\n\n        >>> arr = np.array([0, 1, 2, 3, 3, 4, 5, 6, 1])\n        >>> closest_pair(arr)\n        [[(1,), (8,)], [(3,), (4,)]]\n\n    \"\"\"\n    idxs = [idx for idx in np.ndindex(arr.shape)]\n    outs = []\n    min_dist = arr.max() - arr.min()\n    for idxa in idxs:\n        for idxb in idxs:\n            if idxa == idxb:\n                continue\n            dist = abs(arr[idxa] - arr[idxb])\n            if dist == min_dist:\n                if not [idxb, idxa] in outs:\n                    outs.append([idxa, idxb])\n            elif dist < min_dist:\n                min_dist = dist\n                outs = [[idxa, idxb]]\n    if give == 'indicies':\n        return outs\n    elif give == 'distance':\n        return min_dist\n    else:\n        raise KeyError('give not recognized in closest_pair')\n\n\ndef diff(xi, yi, order=1):\n    \"\"\"Take the numerical derivative of a 1D array.\n\n    Output is mapped onto the original coordinates  using linear interpolation.\n    Expects monotonic xi values.\n\n    Parameters\n    ----------\n    xi : 1D array-like\n        Coordinates.\n    yi : 1D array-like\n        Values.\n    order : positive integer (optional)\n        Order of differentiation.\n\n    Returns\n    -------\n    1D numpy array\n        Numerical derivative. Has the same shape as the input arrays.\n    \"\"\"\n    yi = np.array(yi).copy()\n    flip = False\n    if xi[-1] < xi[0]:\n        xi = np.flipud(xi.copy())\n        yi = np.flipud(yi)\n        flip = True\n    midpoints = (xi[1:] + xi[:-1]) / 2\n    for _ in range(order):\n        d = np.diff(yi)\n        d /= np.diff(xi)\n        yi = np.interp(xi, midpoints, d)\n    if flip:\n        yi = np.flipud(yi)\n    return yi\n\n\ndef fft(xi, yi, axis=0):\n    \"\"\"Take the 1D FFT of an N-dimensional array and return \"sensible\" properly shifted arrays.\n\n    Parameters\n    ----------\n    xi : numpy.ndarray\n        1D array over which the points to be FFT'ed are defined\n    yi : numpy.ndarray\n        ND array with values to FFT\n    axis : int\n        axis of yi to perform FFT over\n\n    Returns\n    -------\n    xi : 1D numpy.ndarray\n        1D array. Conjugate to input xi. Example: if input xi is in the time\n        domain, output xi is in frequency domain.\n    yi : ND numpy.ndarray\n        FFT. Has the same shape as the input array (yi).\n    \"\"\"\n    # xi must be 1D\n    if xi.ndim != 1:\n        raise wt_exceptions.DimensionalityError(1, xi.ndim)\n    # xi must be evenly spaced\n    spacing = np.diff(xi)\n    if not np.allclose(spacing, spacing.mean()):\n        raise RuntimeError('WrightTools.kit.fft: argument xi must be evenly spaced')\n    # fft\n    yi = np.fft.fft(yi, axis=axis)\n    d = (xi.max() - xi.min()) / (xi.size - 1)\n    xi = np.fft.fftfreq(xi.size, d=d)\n    # shift\n    xi = np.fft.fftshift(xi)\n    yi = np.fft.fftshift(yi, axes=axis)\n    return xi, yi\n\n\ndef joint_shape(*args):\n    \"\"\"Given a set of arrays, return the joint shape.\n\n    Parameters\n    ----------\n    args : array-likes\n\n    Returns\n    -------\n    tuple of int\n        Joint shape.\n    \"\"\"\n    if len(args) == 0:\n        return ()\n    shape = []\n    shapes = [a.shape for a in args]\n    ndim = args[0].ndim\n    for i in range(ndim):\n        shape.append(max([s[i] for s in shapes]))\n    return tuple(shape)\n\n\ndef orthogonal(*args):\n    \"\"\"Determine if a set of arrays are orthogonal.\n\n    Parameters\n    ----------\n    args : array-likes or array shapes\n\n    Returns\n    -------\n    bool\n        Array orthogonality condition.\n    \"\"\"\n    for i, arg in enumerate(args):\n        if hasattr(arg, 'shape'):\n            args[i] = arg.shape\n    for s in zip(*args):\n        if np.product(s) != max(s):\n            return False\n    return True\n\n\ndef remove_nans_1D(*args):\n    \"\"\"Remove nans in a set of 1D arrays.\n\n    Removes indicies in all arrays if any array is nan at that index.\n    All input arrays must have the same size.\n\n    Parameters\n    ----------\n    args : 1D arrays\n\n    Returns\n    -------\n    tuple\n        Tuple of 1D arrays in same order as given, with nan indicies removed.\n    \"\"\"\n    vals = np.isnan(args[0])\n    for a in args:\n        vals |= np.isnan(a)\n    return tuple(np.array(a)[vals == False] for a in args)\n\n\ndef share_nans(*arrs):\n    \"\"\"Take a list of nD arrays and return a new list of nD arrays.\n\n    The new list is in the same order as the old list.\n    If one indexed element in an old array is nan then every element for that\n    index in all new arrays in the list is then nan.\n\n    Parameters\n    ----------\n    *arrs : nD arrays.\n\n    Returns\n    -------\n    list\n        List of nD arrays in same order as given, with nan indicies syncronized.\n    \"\"\"\n    nans = np.zeros((arrs[0].shape))\n    for arr in arrs:\n        nans *= arr\n    return tuple([a + nans for a in arrs])\n\n\ndef smooth_1D(arr, n=10):\n    \"\"\"Smooth 1D data by 'running average'.\n\n    Parameters\n    ----------\n    n : int\n        number of points to average\n    \"\"\"\n    for i in range(n, len(arr) - n):\n        window = arr[i - n:i + n].copy()\n        arr[i] = window.mean()\n    return arr\n\n\ndef unique(arr, tolerance=1e-6):\n    \"\"\"Return unique elements in 1D array, within tolerance.\n\n    Parameters\n    ----------\n    arr : array_like\n        Input array. This will be flattened if it is not already 1D.\n    tolerance : number (optional)\n        The tolerance for uniqueness.\n\n    Returns\n    -------\n    array\n        The sorted unique values.\n    \"\"\"\n    arr = sorted(arr.flatten())\n    unique = []\n    while len(arr) > 0:\n        current = arr[0]\n        lis = [xi for xi in arr if np.abs(current - xi) < tolerance]\n        arr = [xi for xi in arr if not np.abs(lis[0] - xi) < tolerance]\n        xi_lis_average = sum(lis) / len(lis)\n        unique.append(xi_lis_average)\n    return np.array(unique)\n\n\ndef valid_index(index, shape):\n    \"\"\"Get a valid index for a broadcastable shape.\n\n    Parameters\n    ----------\n    index : tuple\n        Given index.\n    shape : tuple of int\n        Shape.\n\n    Returns\n    -------\n    tuple\n        Valid index.\n    \"\"\"\n    # append slices to index\n    index = list(index)\n    while len(index) < len(shape):\n        index.append(slice(None))\n    # fill out, in reverse\n    out = []\n    for i, s in zip(index[::-1], shape[::-1]):\n        if s == 1:\n            if isinstance(i, slice):\n                out.append(slice(None))\n            else:\n                out.append(0)\n        else:\n            out.append(i)\n    return tuple(out[::-1])\n", "path": "WrightTools/kit/_array.py"}]}