We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Reduce import time for `sunpy.image.transform`
(I was getting annoyed by our import times, and was inspired by astropy/astropy#4598 to look deeper.)

This one's easy.  Importing `sunpy.image.transform` takes 1.7 seconds on my machine (see below).  0.7 seconds is spent importing `skimage.transform`.  We should defer that import to run-time.

(see #3445 for dealing with `pkg_resources`)

```
python -X importtime -c "import sunpy.image.transform" 2> transform.log
tuna transform.log
```
![transform](https://user-images.githubusercontent.com/991759/67576249-34433a00-f70c-11e9-9cef-4f7b3804e66c.png)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sunpy/image/transform.py`
Content:
```
1 """
2 Functions for geometrical image transformation and warping.
3 """
4 import warnings
5 
6 import numpy as np
7 import scipy.ndimage.interpolation
8 
9 from sunpy.util.exceptions import SunpyUserWarning
10 
11 try:
12     import skimage.transform
13     scikit_image_not_found = False
14 except ImportError:
15     warnings.warn("scikit-image could not be imported. Image rotation will use scipy",
16                   ImportWarning)
17     scikit_image_not_found = True
18 
19 
20 __all__ = ['affine_transform']
21 
22 
23 def affine_transform(image, rmatrix, order=3, scale=1.0, image_center=None,
24                      recenter=False, missing=0.0, use_scipy=False):
25     """
26     Rotates, shifts and scales an image.
27 
28     Will use `skimage.transform.warp` unless scikit-image can't be imported
29     then it will use`scipy.ndimage.interpolation.affine_transform`.
30 
31     Parameters
32     ----------
33     image : `numpy.ndarray`
34         2D image to be rotated.
35     rmatrix : `numpy.ndarray` that is 2x2
36         Linear transformation rotation matrix.
37     order : `int` 0-5, optional
38         Interpolation order to be used, defaults to 3. When using scikit-image this parameter
39         is passed into `skimage.transform.warp` (e.g., 3 corresponds to bi-cubic interpolation).
40         When using scipy it is passed into
41         `scipy.ndimage.interpolation.affine_transform` where it controls the order of the spline.
42     scale : `float`
43         A scale factor for the image with the default being no scaling.
44     image_center : tuple, optional
45         The point in the image to rotate around (axis of rotation).
46         Defaults to the center of the array.
47     recenter : `bool` or array-like, optional
48         Move the axis of rotation to the center of the array or recenter coords.
49         Defaults to `True` i.e., recenter to the center of the array.
50     missing : `float`, optional
51         The value to replace any missing data after the transformation.
52     use_scipy : `bool`, optional
53         Force use of `scipy.ndimage.interpolation.affine_transform`.
54         Will set all "NaNs" in image to zero before doing the transform.
55         Defaults to `False`, unless scikit-image can't be imported.
56 
57     Returns
58     -------
59     `numpy.ndarray`:
60         New rotated, scaled and translated image.
61 
62     Notes
63     -----
64     This algorithm uses an affine transformation as opposed to a polynomial
65     geometrical transformation, which by default is `skimage.transform.warp`.
66     One can specify using `scipy.ndimage.interpolation.affine_transform` as
67     an alternative affine transformation. The two transformations use different
68     algorithms and thus do not give identical output.
69 
70     When using for `skimage.transform.warp` with order >= 4 or using
71     `scipy.ndimage.interpolation.affine_transform` at all, "NaN" values will
72     replaced with zero prior to rotation. No attempt is made to retain the NaN
73     values.
74 
75     Input arrays with integer data are cast to float 64 and can be re-cast using
76     `numpy.ndarray.astype` if desired.
77 
78     Although this function is analogous to the IDL's ``rot`` function, it does not
79     use the same algorithm as the IDL ``rot`` function.
80     IDL's ``rot`` calls the `POLY_2D <https://www.harrisgeospatial.com/docs/poly_2d.html>`__
81     method to calculate the inverse mapping of original to target pixel
82     coordinates. This is a polynomial geometrical transformation.
83     Then optionally it uses a bicubic convolution interpolation
84     algorithm to map the original to target pixel values.
85     """
86     rmatrix = rmatrix / scale
87     array_center = (np.array(image.shape)[::-1]-1)/2.0
88 
89     # Make sure the image center is an array and is where it's supposed to be
90     if image_center is not None:
91         image_center = np.asanyarray(image_center)
92     else:
93         image_center = array_center
94 
95     # Determine center of rotation based on use (or not) of the recenter keyword
96     if recenter:
97         rot_center = array_center
98     else:
99         rot_center = image_center
100 
101     displacement = np.dot(rmatrix, rot_center)
102     shift = image_center - displacement
103 
104     if use_scipy or scikit_image_not_found:
105         if np.any(np.isnan(image)):
106             warnings.warn("Setting NaNs to 0 for SciPy rotation.", SunpyUserWarning)
107         # Transform the image using the scipy affine transform
108         rotated_image = scipy.ndimage.interpolation.affine_transform(
109                 np.nan_to_num(image).T, rmatrix, offset=shift, order=order,
110                 mode='constant', cval=missing).T
111     else:
112         # Make the rotation matrix 3x3 to include translation of the image
113         skmatrix = np.zeros((3, 3))
114         skmatrix[:2, :2] = rmatrix
115         skmatrix[2, 2] = 1.0
116         skmatrix[:2, 2] = shift
117         tform = skimage.transform.AffineTransform(skmatrix)
118 
119         # Transform the image using the skimage function
120         if not np.issubdtype(image.dtype, np.float64):
121             warnings.warn("Input data has been cast to float64.", SunpyUserWarning)
122             adjusted_image = image.astype(np.float64)
123         else:
124             adjusted_image = image.copy()
125         if np.any(np.isnan(adjusted_image)) and order >= 4:
126             warnings.warn("Setting NaNs to 0 for higher-order scikit-image rotation.", SunpyUserWarning)
127             adjusted_image = np.nan_to_num(adjusted_image)
128 
129         rotated_image = skimage.transform.warp(adjusted_image, tform, order=order,
130                                                mode='constant', cval=missing)
131 
132     return rotated_image
133
```
--- 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/sunpy/image/transform.py b/sunpy/image/transform.py
--- a/sunpy/image/transform.py
+++ b/sunpy/image/transform.py
@@ -8,15 +8,6 @@
 
 from sunpy.util.exceptions import SunpyUserWarning
 
-try:
-    import skimage.transform
-    scikit_image_not_found = False
-except ImportError:
-    warnings.warn("scikit-image could not be imported. Image rotation will use scipy",
-                  ImportWarning)
-    scikit_image_not_found = True
-
-
 __all__ = ['affine_transform']
 
 
@@ -84,7 +75,7 @@
     algorithm to map the original to target pixel values.
     """
     rmatrix = rmatrix / scale
-    array_center = (np.array(image.shape)[::-1]-1)/2.0
+    array_center = (np.array(image.shape)[::-1] - 1) / 2.0
 
     # Make sure the image center is an array and is where it's supposed to be
     if image_center is not None:
@@ -100,14 +91,20 @@
 
     displacement = np.dot(rmatrix, rot_center)
     shift = image_center - displacement
-
-    if use_scipy or scikit_image_not_found:
+    if not use_scipy:
+        try:
+            import skimage.transform
+        except ImportError:
+            warnings.warn("scikit-image could not be imported. Image rotation will use scipy",
+                          ImportWarning)
+            use_scipy = True
+    if use_scipy:
         if np.any(np.isnan(image)):
             warnings.warn("Setting NaNs to 0 for SciPy rotation.", SunpyUserWarning)
         # Transform the image using the scipy affine transform
         rotated_image = scipy.ndimage.interpolation.affine_transform(
-                np.nan_to_num(image).T, rmatrix, offset=shift, order=order,
-                mode='constant', cval=missing).T
+            np.nan_to_num(image).T, rmatrix, offset=shift, order=order,
+            mode='constant', cval=missing).T
     else:
         # Make the rotation matrix 3x3 to include translation of the image
         skmatrix = np.zeros((3, 3))

{"golden_diff": "diff --git a/sunpy/image/transform.py b/sunpy/image/transform.py\n--- a/sunpy/image/transform.py\n+++ b/sunpy/image/transform.py\n@@ -8,15 +8,6 @@\n \n from sunpy.util.exceptions import SunpyUserWarning\n \n-try:\n-    import skimage.transform\n-    scikit_image_not_found = False\n-except ImportError:\n-    warnings.warn(\"scikit-image could not be imported. Image rotation will use scipy\",\n-                  ImportWarning)\n-    scikit_image_not_found = True\n-\n-\n __all__ = ['affine_transform']\n \n \n@@ -84,7 +75,7 @@\n     algorithm to map the original to target pixel values.\n     \"\"\"\n     rmatrix = rmatrix / scale\n-    array_center = (np.array(image.shape)[::-1]-1)/2.0\n+    array_center = (np.array(image.shape)[::-1] - 1) / 2.0\n \n     # Make sure the image center is an array and is where it's supposed to be\n     if image_center is not None:\n@@ -100,14 +91,20 @@\n \n     displacement = np.dot(rmatrix, rot_center)\n     shift = image_center - displacement\n-\n-    if use_scipy or scikit_image_not_found:\n+    if not use_scipy:\n+        try:\n+            import skimage.transform\n+        except ImportError:\n+            warnings.warn(\"scikit-image could not be imported. Image rotation will use scipy\",\n+                          ImportWarning)\n+            use_scipy = True\n+    if use_scipy:\n         if np.any(np.isnan(image)):\n             warnings.warn(\"Setting NaNs to 0 for SciPy rotation.\", SunpyUserWarning)\n         # Transform the image using the scipy affine transform\n         rotated_image = scipy.ndimage.interpolation.affine_transform(\n-                np.nan_to_num(image).T, rmatrix, offset=shift, order=order,\n-                mode='constant', cval=missing).T\n+            np.nan_to_num(image).T, rmatrix, offset=shift, order=order,\n+            mode='constant', cval=missing).T\n     else:\n         # Make the rotation matrix 3x3 to include translation of the image\n         skmatrix = np.zeros((3, 3))\n", "issue": "Reduce import time for `sunpy.image.transform`\n(I was getting annoyed by our import times, and was inspired by astropy/astropy#4598 to look deeper.)\r\n\r\nThis one's easy.  Importing `sunpy.image.transform` takes 1.7 seconds on my machine (see below).  0.7 seconds is spent importing `skimage.transform`.  We should defer that import to run-time.\r\n\r\n(see #3445 for dealing with `pkg_resources`)\r\n\r\n```\r\npython -X importtime -c \"import sunpy.image.transform\" 2> transform.log\r\ntuna transform.log\r\n```\r\n![transform](https://user-images.githubusercontent.com/991759/67576249-34433a00-f70c-11e9-9cef-4f7b3804e66c.png)\n", "before_files": [{"content": "\"\"\"\nFunctions for geometrical image transformation and warping.\n\"\"\"\nimport warnings\n\nimport numpy as np\nimport scipy.ndimage.interpolation\n\nfrom sunpy.util.exceptions import SunpyUserWarning\n\ntry:\n    import skimage.transform\n    scikit_image_not_found = False\nexcept ImportError:\n    warnings.warn(\"scikit-image could not be imported. Image rotation will use scipy\",\n                  ImportWarning)\n    scikit_image_not_found = True\n\n\n__all__ = ['affine_transform']\n\n\ndef affine_transform(image, rmatrix, order=3, scale=1.0, image_center=None,\n                     recenter=False, missing=0.0, use_scipy=False):\n    \"\"\"\n    Rotates, shifts and scales an image.\n\n    Will use `skimage.transform.warp` unless scikit-image can't be imported\n    then it will use`scipy.ndimage.interpolation.affine_transform`.\n\n    Parameters\n    ----------\n    image : `numpy.ndarray`\n        2D image to be rotated.\n    rmatrix : `numpy.ndarray` that is 2x2\n        Linear transformation rotation matrix.\n    order : `int` 0-5, optional\n        Interpolation order to be used, defaults to 3. When using scikit-image this parameter\n        is passed into `skimage.transform.warp` (e.g., 3 corresponds to bi-cubic interpolation).\n        When using scipy it is passed into\n        `scipy.ndimage.interpolation.affine_transform` where it controls the order of the spline.\n    scale : `float`\n        A scale factor for the image with the default being no scaling.\n    image_center : tuple, optional\n        The point in the image to rotate around (axis of rotation).\n        Defaults to the center of the array.\n    recenter : `bool` or array-like, optional\n        Move the axis of rotation to the center of the array or recenter coords.\n        Defaults to `True` i.e., recenter to the center of the array.\n    missing : `float`, optional\n        The value to replace any missing data after the transformation.\n    use_scipy : `bool`, optional\n        Force use of `scipy.ndimage.interpolation.affine_transform`.\n        Will set all \"NaNs\" in image to zero before doing the transform.\n        Defaults to `False`, unless scikit-image can't be imported.\n\n    Returns\n    -------\n    `numpy.ndarray`:\n        New rotated, scaled and translated image.\n\n    Notes\n    -----\n    This algorithm uses an affine transformation as opposed to a polynomial\n    geometrical transformation, which by default is `skimage.transform.warp`.\n    One can specify using `scipy.ndimage.interpolation.affine_transform` as\n    an alternative affine transformation. The two transformations use different\n    algorithms and thus do not give identical output.\n\n    When using for `skimage.transform.warp` with order >= 4 or using\n    `scipy.ndimage.interpolation.affine_transform` at all, \"NaN\" values will\n    replaced with zero prior to rotation. No attempt is made to retain the NaN\n    values.\n\n    Input arrays with integer data are cast to float 64 and can be re-cast using\n    `numpy.ndarray.astype` if desired.\n\n    Although this function is analogous to the IDL's ``rot`` function, it does not\n    use the same algorithm as the IDL ``rot`` function.\n    IDL's ``rot`` calls the `POLY_2D <https://www.harrisgeospatial.com/docs/poly_2d.html>`__\n    method to calculate the inverse mapping of original to target pixel\n    coordinates. This is a polynomial geometrical transformation.\n    Then optionally it uses a bicubic convolution interpolation\n    algorithm to map the original to target pixel values.\n    \"\"\"\n    rmatrix = rmatrix / scale\n    array_center = (np.array(image.shape)[::-1]-1)/2.0\n\n    # Make sure the image center is an array and is where it's supposed to be\n    if image_center is not None:\n        image_center = np.asanyarray(image_center)\n    else:\n        image_center = array_center\n\n    # Determine center of rotation based on use (or not) of the recenter keyword\n    if recenter:\n        rot_center = array_center\n    else:\n        rot_center = image_center\n\n    displacement = np.dot(rmatrix, rot_center)\n    shift = image_center - displacement\n\n    if use_scipy or scikit_image_not_found:\n        if np.any(np.isnan(image)):\n            warnings.warn(\"Setting NaNs to 0 for SciPy rotation.\", SunpyUserWarning)\n        # Transform the image using the scipy affine transform\n        rotated_image = scipy.ndimage.interpolation.affine_transform(\n                np.nan_to_num(image).T, rmatrix, offset=shift, order=order,\n                mode='constant', cval=missing).T\n    else:\n        # Make the rotation matrix 3x3 to include translation of the image\n        skmatrix = np.zeros((3, 3))\n        skmatrix[:2, :2] = rmatrix\n        skmatrix[2, 2] = 1.0\n        skmatrix[:2, 2] = shift\n        tform = skimage.transform.AffineTransform(skmatrix)\n\n        # Transform the image using the skimage function\n        if not np.issubdtype(image.dtype, np.float64):\n            warnings.warn(\"Input data has been cast to float64.\", SunpyUserWarning)\n            adjusted_image = image.astype(np.float64)\n        else:\n            adjusted_image = image.copy()\n        if np.any(np.isnan(adjusted_image)) and order >= 4:\n            warnings.warn(\"Setting NaNs to 0 for higher-order scikit-image rotation.\", SunpyUserWarning)\n            adjusted_image = np.nan_to_num(adjusted_image)\n\n        rotated_image = skimage.transform.warp(adjusted_image, tform, order=order,\n                                               mode='constant', cval=missing)\n\n    return rotated_image\n", "path": "sunpy/image/transform.py"}], "after_files": [{"content": "\"\"\"\nFunctions for geometrical image transformation and warping.\n\"\"\"\nimport warnings\n\nimport numpy as np\nimport scipy.ndimage.interpolation\n\nfrom sunpy.util.exceptions import SunpyUserWarning\n\n__all__ = ['affine_transform']\n\n\ndef affine_transform(image, rmatrix, order=3, scale=1.0, image_center=None,\n                     recenter=False, missing=0.0, use_scipy=False):\n    \"\"\"\n    Rotates, shifts and scales an image.\n\n    Will use `skimage.transform.warp` unless scikit-image can't be imported\n    then it will use`scipy.ndimage.interpolation.affine_transform`.\n\n    Parameters\n    ----------\n    image : `numpy.ndarray`\n        2D image to be rotated.\n    rmatrix : `numpy.ndarray` that is 2x2\n        Linear transformation rotation matrix.\n    order : `int` 0-5, optional\n        Interpolation order to be used, defaults to 3. When using scikit-image this parameter\n        is passed into `skimage.transform.warp` (e.g., 3 corresponds to bi-cubic interpolation).\n        When using scipy it is passed into\n        `scipy.ndimage.interpolation.affine_transform` where it controls the order of the spline.\n    scale : `float`\n        A scale factor for the image with the default being no scaling.\n    image_center : tuple, optional\n        The point in the image to rotate around (axis of rotation).\n        Defaults to the center of the array.\n    recenter : `bool` or array-like, optional\n        Move the axis of rotation to the center of the array or recenter coords.\n        Defaults to `True` i.e., recenter to the center of the array.\n    missing : `float`, optional\n        The value to replace any missing data after the transformation.\n    use_scipy : `bool`, optional\n        Force use of `scipy.ndimage.interpolation.affine_transform`.\n        Will set all \"NaNs\" in image to zero before doing the transform.\n        Defaults to `False`, unless scikit-image can't be imported.\n\n    Returns\n    -------\n    `numpy.ndarray`:\n        New rotated, scaled and translated image.\n\n    Notes\n    -----\n    This algorithm uses an affine transformation as opposed to a polynomial\n    geometrical transformation, which by default is `skimage.transform.warp`.\n    One can specify using `scipy.ndimage.interpolation.affine_transform` as\n    an alternative affine transformation. The two transformations use different\n    algorithms and thus do not give identical output.\n\n    When using for `skimage.transform.warp` with order >= 4 or using\n    `scipy.ndimage.interpolation.affine_transform` at all, \"NaN\" values will\n    replaced with zero prior to rotation. No attempt is made to retain the NaN\n    values.\n\n    Input arrays with integer data are cast to float 64 and can be re-cast using\n    `numpy.ndarray.astype` if desired.\n\n    Although this function is analogous to the IDL's ``rot`` function, it does not\n    use the same algorithm as the IDL ``rot`` function.\n    IDL's ``rot`` calls the `POLY_2D <https://www.harrisgeospatial.com/docs/poly_2d.html>`__\n    method to calculate the inverse mapping of original to target pixel\n    coordinates. This is a polynomial geometrical transformation.\n    Then optionally it uses a bicubic convolution interpolation\n    algorithm to map the original to target pixel values.\n    \"\"\"\n    rmatrix = rmatrix / scale\n    array_center = (np.array(image.shape)[::-1] - 1) / 2.0\n\n    # Make sure the image center is an array and is where it's supposed to be\n    if image_center is not None:\n        image_center = np.asanyarray(image_center)\n    else:\n        image_center = array_center\n\n    # Determine center of rotation based on use (or not) of the recenter keyword\n    if recenter:\n        rot_center = array_center\n    else:\n        rot_center = image_center\n\n    displacement = np.dot(rmatrix, rot_center)\n    shift = image_center - displacement\n    if not use_scipy:\n        try:\n            import skimage.transform\n        except ImportError:\n            warnings.warn(\"scikit-image could not be imported. Image rotation will use scipy\",\n                          ImportWarning)\n            use_scipy = True\n    if use_scipy:\n        if np.any(np.isnan(image)):\n            warnings.warn(\"Setting NaNs to 0 for SciPy rotation.\", SunpyUserWarning)\n        # Transform the image using the scipy affine transform\n        rotated_image = scipy.ndimage.interpolation.affine_transform(\n            np.nan_to_num(image).T, rmatrix, offset=shift, order=order,\n            mode='constant', cval=missing).T\n    else:\n        # Make the rotation matrix 3x3 to include translation of the image\n        skmatrix = np.zeros((3, 3))\n        skmatrix[:2, :2] = rmatrix\n        skmatrix[2, 2] = 1.0\n        skmatrix[:2, 2] = shift\n        tform = skimage.transform.AffineTransform(skmatrix)\n\n        # Transform the image using the skimage function\n        if not np.issubdtype(image.dtype, np.float64):\n            warnings.warn(\"Input data has been cast to float64.\", SunpyUserWarning)\n            adjusted_image = image.astype(np.float64)\n        else:\n            adjusted_image = image.copy()\n        if np.any(np.isnan(adjusted_image)) and order >= 4:\n            warnings.warn(\"Setting NaNs to 0 for higher-order scikit-image rotation.\", SunpyUserWarning)\n            adjusted_image = np.nan_to_num(adjusted_image)\n\n        rotated_image = skimage.transform.warp(adjusted_image, tform, order=order,\n                                               mode='constant', cval=missing)\n\n    return rotated_image\n", "path": "sunpy/image/transform.py"}]}