We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Raise issue in calibration for dimensionality too high
https://github.com/wright-group/WrightTools/blob/44da87cf4dfa18f87bdd699b832066ace50f6ec1/WrightTools/calibration.py#L263

This one I could see requiring changes to gracefully catch the exception thrown here, but Feel an exception is more clear than a print/return


--- 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/calibration.py`
Content:
```
1 """Calibration."""
2 
3 
4 # --- import --------------------------------------------------------------------------------------
5 
6 
7 from __future__ import absolute_import, division, print_function, unicode_literals
8 
9 import os
10 import collections
11 
12 import numpy as np
13 
14 import scipy
15 
16 import matplotlib
17 import matplotlib.pyplot as plt
18 
19 from . import units as wt_units
20 from . import kit as wt_kit
21 from . import artists as wt_artists
22 
23 matplotlib.rcParams['font.size'] = 14
24 
25 
26 # --- define --------------------------------------------------------------------------------------
27 
28 
29 cmap = wt_artists.colormaps['default']
30 cmap.set_bad([0.75] * 3, 1.)
31 cmap.set_under([0.75] * 3)
32 
33 
34 def get_label(name, units):
35     """Get label.
36 
37     Parameters
38     ----------
39     name : string
40         Name.
41     units : string
42         Units.
43 
44     Returns
45     -------
46     string
47         Label.
48     """
49     # units kind
50     units_kind = None
51     for dic in wt_units.unit_dicts:
52         if units in dic.keys():
53             units_kind = dic['kind']
54 
55     # units string
56     d = getattr(wt_units, units_kind)
57     units_string = r'$\mathsf{('
58     units_string += d[units][2]
59     units_string += r')}$'
60     # finish
61     out = ' '.join([name, units_string])
62     return out
63 
64 
65 # --- calibration class ---------------------------------------------------------------------------
66 
67 
68 class Calibration:
69     """Container for unstructured calibration data."""
70 
71     def __init__(self, axis_names, axis_units, points, values, name='calibration',
72                  note=''):
73         """Create an unstructured calibration object.
74 
75         Parameters
76         ----------
77         points : list of lists
78             List or list-like of lists. May be a 2D numpy array.
79         axis_units : list of strings
80             Units for each axis.
81         values : 1D array-like
82             Corrections for each coordinate.
83         name : string (optional)
84             Name of calibration. Default is 'calibration'
85         note : string (optional)
86             Note about calibration. Default is an empty string.
87         """
88         self.axis_names = axis_names
89         self.axis_units = axis_units
90         self.dimensionality = len(self.axis_names)
91         self.points = np.array(points)
92         self.values = np.array(values)
93         self.name = name
94         self.note = note
95         self._interpolate()
96 
97     def _interpolate(self):
98         """(Re)create the interpolator using the current points and values."""
99         self._sort()
100         if self.dimensionality == 1:
101             self.interpolator = wt_kit.Spline(self.points[0], self.values, k=1, s=0)
102         else:
103             self.interpolator = scipy.interpolate.LinearNDInterpolator(self.points.T, self.values)
104 
105     def _sort(self):
106         """Sort data by all axes.
107 
108         First axis will be strictly ascending, second
109         will be ascending within groups sharing the same value in the first
110         axis etc.
111         """
112         ind = np.lexsort((self.points[::-1]))
113         self.points = self.points[:, ind]
114         self.values = self.values[ind]
115 
116     def append(self, points, values, units='same'):
117         """Add new data to the calibration.
118 
119         Parameters
120         ----------
121         points : list of lists
122             List or list-like of lists. May be a 2D numpy array.
123         values : 1D array-like
124             Corrections for each coordinate.
125         units : 'same' or list of strings (optional)
126             Units of points. Default is 'same'.
127         """
128         points = np.array(points)
129         values = np.array(values)
130         if not units == 'same':
131             for i, p in enumerate(points):
132                 points[i] = wt_units.converter(p, units[i], self.axis_units[i])
133         self.points = np.hstack([self.points, points])
134         self.values = np.hstack([self.values, values])
135         self._interpolate()
136 
137     def convert(self, axis_units):
138         """Convert axes to new units.
139 
140         Parameters
141         ----------
142         axis_units : list of string
143             New units for each axis.
144         """
145         for i, p in enumerate(self.points):
146             self.points[i] = wt_units.converter(p, self.axis_units[i], axis_units[i])
147         self.axis_units = axis_units
148         self._interpolate()
149 
150     def get_positions(self, value, **kwargs):
151         """Get all valid coordinates.
152 
153         Returns
154         -------
155         list of dictionaries
156             All valid coordinates, defined for all axes. List may be empty.
157         """
158         # TODO: complete documentation
159         if self.dimensionality == 1:
160             # TODO:
161             out = []
162         else:
163             # TODO: unhack...
164             xi = np.linspace(self.points[1].min(), self.points[1].max(), 101)
165             yi = np.array([self.get_value([kwargs['color'], x]) for x in xi])
166             i = np.argmin(np.abs(yi - value))
167             out = [{'color': kwargs['color'], 'angle': xi[i]}]
168         return out
169 
170     def get_value(self, positions, units='same'):
171         """Get the value at some particular coordinate using linear interpolation.
172 
173         Parameters
174         ----------
175         positions : list of numbers
176             Coordinate to evaluate at.
177         units : 'same' or list of strings (optional)
178             Units of positions. Default is 'same'.
179         """
180         return self.interpolator(*positions)
181 
182     def map_points(self, points, units='same'):
183         """Map the points onto new points using interpolation.
184 
185         Parameters
186         ----------
187         points : int or array
188             The number of new points (between current limits) or the new points
189             themselves.
190         units : str (optional.)
191             The input units if given as array. Default is same. Units of coset
192             object are not changed.
193         """
194         # get new points in input units
195         if isinstance(points, int):
196             limits = self.get_limits(self.units)
197             new_points = np.linspace(limits[0], limits[1], points)
198         else:
199             new_points = points
200         # convert new points to local units
201         if units == 'same':
202             units = self.control_units
203         new_points = np.sort(wt_units.converter(new_points, units, self.control_units))
204         new_values = self.get_offset(new_points)
205         # finish
206         self.points = new_points
207         self.values = new_values
208 
209     def plot(self, autosave=False, save_directory=None, file_name=None):
210         """Plot the calibration.
211 
212         Parameters
213         ----------
214         autosave : boolean (optional)
215             Toggle automatic saving. Default is False.
216         save_directory : string or None
217             Location to save file. If None (default), uses current working
218             directory.
219         file_name : string (optional)
220             Name for output image. If None (default), uses own name and a
221             timestamp.
222 
223         Returns
224         -------
225         output
226             Save path if autosave is True, fig object if autosave is False.
227 
228         .. note:: Only works for one and two-dimensional calibrations at this time.
229 
230         """
231         if self.dimensionality == 1:
232             fig, gs = wt_artists.create_figure(cols=[1])
233             ax = plt.subplot(gs[0])
234             xi = self.points[0]
235             yi = self.values
236             ax.scatter(xi, yi, c='k')
237             xi = np.linspace(self.points[0].min(), self.points[0].max(), 1000)
238             yi = self.interpolator(xi)
239             ax.plot(xi, yi, c='k', lw=2)
240             ax.grid()
241             plt.xticks(rotation=45)
242             ax.set_xlabel(get_label(self.axis_names[0], self.axis_units[0]), fontsize=18)
243 
244             wt_artists._title(fig, self.name)
245         elif self.dimensionality == 2:
246             fig, gs = wt_artists.create_figure(cols=[1, 'cbar'])
247             ax = plt.subplot(gs[0, 0])
248             ax.patch.set_facecolor([0.75] * 3)
249             levels = np.linspace(self.values.min(), self.values.max(), 200)
250             ax.tricontourf(self.points[0], self.points[1], self.values, cmap=cmap, levels=levels)
251             ax.scatter(self.points[0], self.points[1], c='k', s=3, marker='o')
252             ax.set_xlim(self.points[0].min(), self.points[0].max())
253             ax.set_ylim(self.points[1].min(), self.points[1].max())
254             ax.grid()
255             plt.xticks(rotation=45)
256             ax.set_xlabel(get_label(self.axis_names[0], self.axis_units[0]), fontsize=18)
257             ax.set_ylabel(get_label(self.axis_names[1], self.axis_units[1]), fontsize=18)
258             cax = plt.subplot(gs[0, 1])
259             ticks = np.linspace(self.values.min(), self.values.max(), 11)
260             wt_artists.plot_colorbar(cax=cax, ticks=ticks)
261             plt.suptitle(self.name, fontsize=20)
262         else:
263             print('cannot plot---dimensionality too high')
264             return
265         # save
266         if autosave:
267             if save_directory is None:
268                 save_directory = os.getcwd()
269             if file_name is None:
270                 time_stamp = wt_kit.TimeStamp()
271                 file_name = ' '.join([self.name, time_stamp.path]) + '.png'
272             save_path = os.path.join(save_directory, file_name)
273             wt_artists.savefig(save_path, fig=fig)
274             return save_path
275         return fig
276 
277     def save(self, save_directory=None, file_name=None, plot=True,
278              verbose=True):
279         """Save the calibration.
280 
281         Parameters
282         ----------
283         save_directory : string or None (optional)
284             Directory to save to. If None (default), saves to current working
285             directory.
286         file_name : string or None (optional)
287             Name for output file. If None (default), uses own name and a
288             timestamp.
289         plot : boolean (optional)
290             Toggle saving a plot of the calibration as well. Default is True.
291         verbose : boolean (optional)
292             Toggle talkback. Default is True.
293 
294         Returns
295         -------
296         string
297             Full path to saved file.
298         """
299         time_stamp = wt_kit.TimeStamp()
300         # get save path
301         if save_directory is None:
302             save_directory = os.getcwd()
303         if file_name is None:
304             file_name = ' - '.join([self.name, time_stamp.path]) + '.calibration'
305         file_path = os.path.join(save_directory, file_name)
306         # write to file
307         headers = collections.OrderedDict()
308         headers['name'] = self.name
309         headers['file created'] = time_stamp.RFC3339
310         headers['axis names'] = self.axis_names
311         headers['axis units'] = self.axis_units
312         headers['note'] = self.note
313         file_path = wt_kit.write_headers(file_path, headers)
314         X = np.vstack([self.points, self.values]).T
315         with open(file_path, 'ab') as f:
316             np.savetxt(f, X, fmt=str('%6e'), delimiter='\t')
317         # plot
318         if plot:
319             save_directory = save_directory
320             file_name = os.path.basename(file_path).replace('.calibration', '.png')
321             self.plot(autosave=True, save_directory=save_directory, file_name=file_name)
322         # finish
323         if verbose:
324             print('calibration saved at {}'.format(file_path))
325         return file_path
326 
327 
328 # --- load method ---------------------------------------------------------------------------------
329 
330 
331 def from_file(path):
332     """Generate a calibration object from a file.
333 
334     Parameters
335     ----------
336     path : string
337         Filepath.
338 
339     Returns
340     -------
341     WrightTools.calibration.Calibration
342     """
343     # get raw information from file
344     headers = wt_kit.read_headers(path)
345     arr = np.genfromtxt(path).T
346     name = os.path.basename(path).split(' - ')[0]
347     # construct calibration object
348     points = arr[0:-1]
349     values = arr[-1]
350     axis_names = headers['axis names']
351     axis_units = headers['axis units']
352     name = headers['name']
353     note = headers['note']
354     c = Calibration(axis_names, axis_units, points, values, name=name, note=note)
355     # finish
356     return c
357
```
--- 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/calibration.py b/WrightTools/calibration.py
--- a/WrightTools/calibration.py
+++ b/WrightTools/calibration.py
@@ -260,8 +260,7 @@
             wt_artists.plot_colorbar(cax=cax, ticks=ticks)
             plt.suptitle(self.name, fontsize=20)
         else:
-            print('cannot plot---dimensionality too high')
-            return
+            raise wt_exceptions.DimensionalityError("{1, 2}", self.dimensionality)
         # save
         if autosave:
             if save_directory is None:

{"golden_diff": "diff --git a/WrightTools/calibration.py b/WrightTools/calibration.py\n--- a/WrightTools/calibration.py\n+++ b/WrightTools/calibration.py\n@@ -260,8 +260,7 @@\n             wt_artists.plot_colorbar(cax=cax, ticks=ticks)\n             plt.suptitle(self.name, fontsize=20)\n         else:\n-            print('cannot plot---dimensionality too high')\n-            return\n+            raise wt_exceptions.DimensionalityError(\"{1, 2}\", self.dimensionality)\n         # save\n         if autosave:\n             if save_directory is None:\n", "issue": "Raise issue in calibration for dimensionality too high\nhttps://github.com/wright-group/WrightTools/blob/44da87cf4dfa18f87bdd699b832066ace50f6ec1/WrightTools/calibration.py#L263\r\n\r\nThis one I could see requiring changes to gracefully catch the exception thrown here, but Feel an exception is more clear than a print/return\r\n\n", "before_files": [{"content": "\"\"\"Calibration.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport os\nimport collections\n\nimport numpy as np\n\nimport scipy\n\nimport matplotlib\nimport matplotlib.pyplot as plt\n\nfrom . import units as wt_units\nfrom . import kit as wt_kit\nfrom . import artists as wt_artists\n\nmatplotlib.rcParams['font.size'] = 14\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\ncmap = wt_artists.colormaps['default']\ncmap.set_bad([0.75] * 3, 1.)\ncmap.set_under([0.75] * 3)\n\n\ndef get_label(name, units):\n    \"\"\"Get label.\n\n    Parameters\n    ----------\n    name : string\n        Name.\n    units : string\n        Units.\n\n    Returns\n    -------\n    string\n        Label.\n    \"\"\"\n    # units kind\n    units_kind = None\n    for dic in wt_units.unit_dicts:\n        if units in dic.keys():\n            units_kind = dic['kind']\n\n    # units string\n    d = getattr(wt_units, units_kind)\n    units_string = r'$\\mathsf{('\n    units_string += d[units][2]\n    units_string += r')}$'\n    # finish\n    out = ' '.join([name, units_string])\n    return out\n\n\n# --- calibration class ---------------------------------------------------------------------------\n\n\nclass Calibration:\n    \"\"\"Container for unstructured calibration data.\"\"\"\n\n    def __init__(self, axis_names, axis_units, points, values, name='calibration',\n                 note=''):\n        \"\"\"Create an unstructured calibration object.\n\n        Parameters\n        ----------\n        points : list of lists\n            List or list-like of lists. May be a 2D numpy array.\n        axis_units : list of strings\n            Units for each axis.\n        values : 1D array-like\n            Corrections for each coordinate.\n        name : string (optional)\n            Name of calibration. Default is 'calibration'\n        note : string (optional)\n            Note about calibration. Default is an empty string.\n        \"\"\"\n        self.axis_names = axis_names\n        self.axis_units = axis_units\n        self.dimensionality = len(self.axis_names)\n        self.points = np.array(points)\n        self.values = np.array(values)\n        self.name = name\n        self.note = note\n        self._interpolate()\n\n    def _interpolate(self):\n        \"\"\"(Re)create the interpolator using the current points and values.\"\"\"\n        self._sort()\n        if self.dimensionality == 1:\n            self.interpolator = wt_kit.Spline(self.points[0], self.values, k=1, s=0)\n        else:\n            self.interpolator = scipy.interpolate.LinearNDInterpolator(self.points.T, self.values)\n\n    def _sort(self):\n        \"\"\"Sort data by all axes.\n\n        First axis will be strictly ascending, second\n        will be ascending within groups sharing the same value in the first\n        axis etc.\n        \"\"\"\n        ind = np.lexsort((self.points[::-1]))\n        self.points = self.points[:, ind]\n        self.values = self.values[ind]\n\n    def append(self, points, values, units='same'):\n        \"\"\"Add new data to the calibration.\n\n        Parameters\n        ----------\n        points : list of lists\n            List or list-like of lists. May be a 2D numpy array.\n        values : 1D array-like\n            Corrections for each coordinate.\n        units : 'same' or list of strings (optional)\n            Units of points. Default is 'same'.\n        \"\"\"\n        points = np.array(points)\n        values = np.array(values)\n        if not units == 'same':\n            for i, p in enumerate(points):\n                points[i] = wt_units.converter(p, units[i], self.axis_units[i])\n        self.points = np.hstack([self.points, points])\n        self.values = np.hstack([self.values, values])\n        self._interpolate()\n\n    def convert(self, axis_units):\n        \"\"\"Convert axes to new units.\n\n        Parameters\n        ----------\n        axis_units : list of string\n            New units for each axis.\n        \"\"\"\n        for i, p in enumerate(self.points):\n            self.points[i] = wt_units.converter(p, self.axis_units[i], axis_units[i])\n        self.axis_units = axis_units\n        self._interpolate()\n\n    def get_positions(self, value, **kwargs):\n        \"\"\"Get all valid coordinates.\n\n        Returns\n        -------\n        list of dictionaries\n            All valid coordinates, defined for all axes. List may be empty.\n        \"\"\"\n        # TODO: complete documentation\n        if self.dimensionality == 1:\n            # TODO:\n            out = []\n        else:\n            # TODO: unhack...\n            xi = np.linspace(self.points[1].min(), self.points[1].max(), 101)\n            yi = np.array([self.get_value([kwargs['color'], x]) for x in xi])\n            i = np.argmin(np.abs(yi - value))\n            out = [{'color': kwargs['color'], 'angle': xi[i]}]\n        return out\n\n    def get_value(self, positions, units='same'):\n        \"\"\"Get the value at some particular coordinate using linear interpolation.\n\n        Parameters\n        ----------\n        positions : list of numbers\n            Coordinate to evaluate at.\n        units : 'same' or list of strings (optional)\n            Units of positions. Default is 'same'.\n        \"\"\"\n        return self.interpolator(*positions)\n\n    def map_points(self, points, units='same'):\n        \"\"\"Map the points onto new points using interpolation.\n\n        Parameters\n        ----------\n        points : int or array\n            The number of new points (between current limits) or the new points\n            themselves.\n        units : str (optional.)\n            The input units if given as array. Default is same. Units of coset\n            object are not changed.\n        \"\"\"\n        # get new points in input units\n        if isinstance(points, int):\n            limits = self.get_limits(self.units)\n            new_points = np.linspace(limits[0], limits[1], points)\n        else:\n            new_points = points\n        # convert new points to local units\n        if units == 'same':\n            units = self.control_units\n        new_points = np.sort(wt_units.converter(new_points, units, self.control_units))\n        new_values = self.get_offset(new_points)\n        # finish\n        self.points = new_points\n        self.values = new_values\n\n    def plot(self, autosave=False, save_directory=None, file_name=None):\n        \"\"\"Plot the calibration.\n\n        Parameters\n        ----------\n        autosave : boolean (optional)\n            Toggle automatic saving. Default is False.\n        save_directory : string or None\n            Location to save file. If None (default), uses current working\n            directory.\n        file_name : string (optional)\n            Name for output image. If None (default), uses own name and a\n            timestamp.\n\n        Returns\n        -------\n        output\n            Save path if autosave is True, fig object if autosave is False.\n\n        .. note:: Only works for one and two-dimensional calibrations at this time.\n\n        \"\"\"\n        if self.dimensionality == 1:\n            fig, gs = wt_artists.create_figure(cols=[1])\n            ax = plt.subplot(gs[0])\n            xi = self.points[0]\n            yi = self.values\n            ax.scatter(xi, yi, c='k')\n            xi = np.linspace(self.points[0].min(), self.points[0].max(), 1000)\n            yi = self.interpolator(xi)\n            ax.plot(xi, yi, c='k', lw=2)\n            ax.grid()\n            plt.xticks(rotation=45)\n            ax.set_xlabel(get_label(self.axis_names[0], self.axis_units[0]), fontsize=18)\n\n            wt_artists._title(fig, self.name)\n        elif self.dimensionality == 2:\n            fig, gs = wt_artists.create_figure(cols=[1, 'cbar'])\n            ax = plt.subplot(gs[0, 0])\n            ax.patch.set_facecolor([0.75] * 3)\n            levels = np.linspace(self.values.min(), self.values.max(), 200)\n            ax.tricontourf(self.points[0], self.points[1], self.values, cmap=cmap, levels=levels)\n            ax.scatter(self.points[0], self.points[1], c='k', s=3, marker='o')\n            ax.set_xlim(self.points[0].min(), self.points[0].max())\n            ax.set_ylim(self.points[1].min(), self.points[1].max())\n            ax.grid()\n            plt.xticks(rotation=45)\n            ax.set_xlabel(get_label(self.axis_names[0], self.axis_units[0]), fontsize=18)\n            ax.set_ylabel(get_label(self.axis_names[1], self.axis_units[1]), fontsize=18)\n            cax = plt.subplot(gs[0, 1])\n            ticks = np.linspace(self.values.min(), self.values.max(), 11)\n            wt_artists.plot_colorbar(cax=cax, ticks=ticks)\n            plt.suptitle(self.name, fontsize=20)\n        else:\n            print('cannot plot---dimensionality too high')\n            return\n        # save\n        if autosave:\n            if save_directory is None:\n                save_directory = os.getcwd()\n            if file_name is None:\n                time_stamp = wt_kit.TimeStamp()\n                file_name = ' '.join([self.name, time_stamp.path]) + '.png'\n            save_path = os.path.join(save_directory, file_name)\n            wt_artists.savefig(save_path, fig=fig)\n            return save_path\n        return fig\n\n    def save(self, save_directory=None, file_name=None, plot=True,\n             verbose=True):\n        \"\"\"Save the calibration.\n\n        Parameters\n        ----------\n        save_directory : string or None (optional)\n            Directory to save to. If None (default), saves to current working\n            directory.\n        file_name : string or None (optional)\n            Name for output file. If None (default), uses own name and a\n            timestamp.\n        plot : boolean (optional)\n            Toggle saving a plot of the calibration as well. Default is True.\n        verbose : boolean (optional)\n            Toggle talkback. Default is True.\n\n        Returns\n        -------\n        string\n            Full path to saved file.\n        \"\"\"\n        time_stamp = wt_kit.TimeStamp()\n        # get save path\n        if save_directory is None:\n            save_directory = os.getcwd()\n        if file_name is None:\n            file_name = ' - '.join([self.name, time_stamp.path]) + '.calibration'\n        file_path = os.path.join(save_directory, file_name)\n        # write to file\n        headers = collections.OrderedDict()\n        headers['name'] = self.name\n        headers['file created'] = time_stamp.RFC3339\n        headers['axis names'] = self.axis_names\n        headers['axis units'] = self.axis_units\n        headers['note'] = self.note\n        file_path = wt_kit.write_headers(file_path, headers)\n        X = np.vstack([self.points, self.values]).T\n        with open(file_path, 'ab') as f:\n            np.savetxt(f, X, fmt=str('%6e'), delimiter='\\t')\n        # plot\n        if plot:\n            save_directory = save_directory\n            file_name = os.path.basename(file_path).replace('.calibration', '.png')\n            self.plot(autosave=True, save_directory=save_directory, file_name=file_name)\n        # finish\n        if verbose:\n            print('calibration saved at {}'.format(file_path))\n        return file_path\n\n\n# --- load method ---------------------------------------------------------------------------------\n\n\ndef from_file(path):\n    \"\"\"Generate a calibration object from a file.\n\n    Parameters\n    ----------\n    path : string\n        Filepath.\n\n    Returns\n    -------\n    WrightTools.calibration.Calibration\n    \"\"\"\n    # get raw information from file\n    headers = wt_kit.read_headers(path)\n    arr = np.genfromtxt(path).T\n    name = os.path.basename(path).split(' - ')[0]\n    # construct calibration object\n    points = arr[0:-1]\n    values = arr[-1]\n    axis_names = headers['axis names']\n    axis_units = headers['axis units']\n    name = headers['name']\n    note = headers['note']\n    c = Calibration(axis_names, axis_units, points, values, name=name, note=note)\n    # finish\n    return c\n", "path": "WrightTools/calibration.py"}], "after_files": [{"content": "\"\"\"Calibration.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport os\nimport collections\n\nimport numpy as np\n\nimport scipy\n\nimport matplotlib\nimport matplotlib.pyplot as plt\n\nfrom . import units as wt_units\nfrom . import kit as wt_kit\nfrom . import artists as wt_artists\n\nmatplotlib.rcParams['font.size'] = 14\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\ncmap = wt_artists.colormaps['default']\ncmap.set_bad([0.75] * 3, 1.)\ncmap.set_under([0.75] * 3)\n\n\ndef get_label(name, units):\n    \"\"\"Get label.\n\n    Parameters\n    ----------\n    name : string\n        Name.\n    units : string\n        Units.\n\n    Returns\n    -------\n    string\n        Label.\n    \"\"\"\n    # units kind\n    units_kind = None\n    for dic in wt_units.unit_dicts:\n        if units in dic.keys():\n            units_kind = dic['kind']\n\n    # units string\n    d = getattr(wt_units, units_kind)\n    units_string = r'$\\mathsf{('\n    units_string += d[units][2]\n    units_string += r')}$'\n    # finish\n    out = ' '.join([name, units_string])\n    return out\n\n\n# --- calibration class ---------------------------------------------------------------------------\n\n\nclass Calibration:\n    \"\"\"Container for unstructured calibration data.\"\"\"\n\n    def __init__(self, axis_names, axis_units, points, values, name='calibration',\n                 note=''):\n        \"\"\"Create an unstructured calibration object.\n\n        Parameters\n        ----------\n        points : list of lists\n            List or list-like of lists. May be a 2D numpy array.\n        axis_units : list of strings\n            Units for each axis.\n        values : 1D array-like\n            Corrections for each coordinate.\n        name : string (optional)\n            Name of calibration. Default is 'calibration'\n        note : string (optional)\n            Note about calibration. Default is an empty string.\n        \"\"\"\n        self.axis_names = axis_names\n        self.axis_units = axis_units\n        self.dimensionality = len(self.axis_names)\n        self.points = np.array(points)\n        self.values = np.array(values)\n        self.name = name\n        self.note = note\n        self._interpolate()\n\n    def _interpolate(self):\n        \"\"\"(Re)create the interpolator using the current points and values.\"\"\"\n        self._sort()\n        if self.dimensionality == 1:\n            self.interpolator = wt_kit.Spline(self.points[0], self.values, k=1, s=0)\n        else:\n            self.interpolator = scipy.interpolate.LinearNDInterpolator(self.points.T, self.values)\n\n    def _sort(self):\n        \"\"\"Sort data by all axes.\n\n        First axis will be strictly ascending, second\n        will be ascending within groups sharing the same value in the first\n        axis etc.\n        \"\"\"\n        ind = np.lexsort((self.points[::-1]))\n        self.points = self.points[:, ind]\n        self.values = self.values[ind]\n\n    def append(self, points, values, units='same'):\n        \"\"\"Add new data to the calibration.\n\n        Parameters\n        ----------\n        points : list of lists\n            List or list-like of lists. May be a 2D numpy array.\n        values : 1D array-like\n            Corrections for each coordinate.\n        units : 'same' or list of strings (optional)\n            Units of points. Default is 'same'.\n        \"\"\"\n        points = np.array(points)\n        values = np.array(values)\n        if not units == 'same':\n            for i, p in enumerate(points):\n                points[i] = wt_units.converter(p, units[i], self.axis_units[i])\n        self.points = np.hstack([self.points, points])\n        self.values = np.hstack([self.values, values])\n        self._interpolate()\n\n    def convert(self, axis_units):\n        \"\"\"Convert axes to new units.\n\n        Parameters\n        ----------\n        axis_units : list of string\n            New units for each axis.\n        \"\"\"\n        for i, p in enumerate(self.points):\n            self.points[i] = wt_units.converter(p, self.axis_units[i], axis_units[i])\n        self.axis_units = axis_units\n        self._interpolate()\n\n    def get_positions(self, value, **kwargs):\n        \"\"\"Get all valid coordinates.\n\n        Returns\n        -------\n        list of dictionaries\n            All valid coordinates, defined for all axes. List may be empty.\n        \"\"\"\n        # TODO: complete documentation\n        if self.dimensionality == 1:\n            # TODO:\n            out = []\n        else:\n            # TODO: unhack...\n            xi = np.linspace(self.points[1].min(), self.points[1].max(), 101)\n            yi = np.array([self.get_value([kwargs['color'], x]) for x in xi])\n            i = np.argmin(np.abs(yi - value))\n            out = [{'color': kwargs['color'], 'angle': xi[i]}]\n        return out\n\n    def get_value(self, positions, units='same'):\n        \"\"\"Get the value at some particular coordinate using linear interpolation.\n\n        Parameters\n        ----------\n        positions : list of numbers\n            Coordinate to evaluate at.\n        units : 'same' or list of strings (optional)\n            Units of positions. Default is 'same'.\n        \"\"\"\n        return self.interpolator(*positions)\n\n    def map_points(self, points, units='same'):\n        \"\"\"Map the points onto new points using interpolation.\n\n        Parameters\n        ----------\n        points : int or array\n            The number of new points (between current limits) or the new points\n            themselves.\n        units : str (optional.)\n            The input units if given as array. Default is same. Units of coset\n            object are not changed.\n        \"\"\"\n        # get new points in input units\n        if isinstance(points, int):\n            limits = self.get_limits(self.units)\n            new_points = np.linspace(limits[0], limits[1], points)\n        else:\n            new_points = points\n        # convert new points to local units\n        if units == 'same':\n            units = self.control_units\n        new_points = np.sort(wt_units.converter(new_points, units, self.control_units))\n        new_values = self.get_offset(new_points)\n        # finish\n        self.points = new_points\n        self.values = new_values\n\n    def plot(self, autosave=False, save_directory=None, file_name=None):\n        \"\"\"Plot the calibration.\n\n        Parameters\n        ----------\n        autosave : boolean (optional)\n            Toggle automatic saving. Default is False.\n        save_directory : string or None\n            Location to save file. If None (default), uses current working\n            directory.\n        file_name : string (optional)\n            Name for output image. If None (default), uses own name and a\n            timestamp.\n\n        Returns\n        -------\n        output\n            Save path if autosave is True, fig object if autosave is False.\n\n        .. note:: Only works for one and two-dimensional calibrations at this time.\n\n        \"\"\"\n        if self.dimensionality == 1:\n            fig, gs = wt_artists.create_figure(cols=[1])\n            ax = plt.subplot(gs[0])\n            xi = self.points[0]\n            yi = self.values\n            ax.scatter(xi, yi, c='k')\n            xi = np.linspace(self.points[0].min(), self.points[0].max(), 1000)\n            yi = self.interpolator(xi)\n            ax.plot(xi, yi, c='k', lw=2)\n            ax.grid()\n            plt.xticks(rotation=45)\n            ax.set_xlabel(get_label(self.axis_names[0], self.axis_units[0]), fontsize=18)\n\n            wt_artists._title(fig, self.name)\n        elif self.dimensionality == 2:\n            fig, gs = wt_artists.create_figure(cols=[1, 'cbar'])\n            ax = plt.subplot(gs[0, 0])\n            ax.patch.set_facecolor([0.75] * 3)\n            levels = np.linspace(self.values.min(), self.values.max(), 200)\n            ax.tricontourf(self.points[0], self.points[1], self.values, cmap=cmap, levels=levels)\n            ax.scatter(self.points[0], self.points[1], c='k', s=3, marker='o')\n            ax.set_xlim(self.points[0].min(), self.points[0].max())\n            ax.set_ylim(self.points[1].min(), self.points[1].max())\n            ax.grid()\n            plt.xticks(rotation=45)\n            ax.set_xlabel(get_label(self.axis_names[0], self.axis_units[0]), fontsize=18)\n            ax.set_ylabel(get_label(self.axis_names[1], self.axis_units[1]), fontsize=18)\n            cax = plt.subplot(gs[0, 1])\n            ticks = np.linspace(self.values.min(), self.values.max(), 11)\n            wt_artists.plot_colorbar(cax=cax, ticks=ticks)\n            plt.suptitle(self.name, fontsize=20)\n        else:\n            raise wt_exceptions.DimensionalityError(\"{1, 2}\", self.dimensionality)\n        # save\n        if autosave:\n            if save_directory is None:\n                save_directory = os.getcwd()\n            if file_name is None:\n                time_stamp = wt_kit.TimeStamp()\n                file_name = ' '.join([self.name, time_stamp.path]) + '.png'\n            save_path = os.path.join(save_directory, file_name)\n            wt_artists.savefig(save_path, fig=fig)\n            return save_path\n        return fig\n\n    def save(self, save_directory=None, file_name=None, plot=True,\n             verbose=True):\n        \"\"\"Save the calibration.\n\n        Parameters\n        ----------\n        save_directory : string or None (optional)\n            Directory to save to. If None (default), saves to current working\n            directory.\n        file_name : string or None (optional)\n            Name for output file. If None (default), uses own name and a\n            timestamp.\n        plot : boolean (optional)\n            Toggle saving a plot of the calibration as well. Default is True.\n        verbose : boolean (optional)\n            Toggle talkback. Default is True.\n\n        Returns\n        -------\n        string\n            Full path to saved file.\n        \"\"\"\n        time_stamp = wt_kit.TimeStamp()\n        # get save path\n        if save_directory is None:\n            save_directory = os.getcwd()\n        if file_name is None:\n            file_name = ' - '.join([self.name, time_stamp.path]) + '.calibration'\n        file_path = os.path.join(save_directory, file_name)\n        # write to file\n        headers = collections.OrderedDict()\n        headers['name'] = self.name\n        headers['file created'] = time_stamp.RFC3339\n        headers['axis names'] = self.axis_names\n        headers['axis units'] = self.axis_units\n        headers['note'] = self.note\n        file_path = wt_kit.write_headers(file_path, headers)\n        X = np.vstack([self.points, self.values]).T\n        with open(file_path, 'ab') as f:\n            np.savetxt(f, X, fmt=str('%6e'), delimiter='\\t')\n        # plot\n        if plot:\n            save_directory = save_directory\n            file_name = os.path.basename(file_path).replace('.calibration', '.png')\n            self.plot(autosave=True, save_directory=save_directory, file_name=file_name)\n        # finish\n        if verbose:\n            print('calibration saved at {}'.format(file_path))\n        return file_path\n\n\n# --- load method ---------------------------------------------------------------------------------\n\n\ndef from_file(path):\n    \"\"\"Generate a calibration object from a file.\n\n    Parameters\n    ----------\n    path : string\n        Filepath.\n\n    Returns\n    -------\n    WrightTools.calibration.Calibration\n    \"\"\"\n    # get raw information from file\n    headers = wt_kit.read_headers(path)\n    arr = np.genfromtxt(path).T\n    name = os.path.basename(path).split(' - ')[0]\n    # construct calibration object\n    points = arr[0:-1]\n    values = arr[-1]\n    axis_names = headers['axis names']\n    axis_units = headers['axis units']\n    name = headers['name']\n    note = headers['note']\n    c = Calibration(axis_names, axis_units, points, values, name=name, note=note)\n    # finish\n    return c\n", "path": "WrightTools/calibration.py"}]}