We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
compatibility issue with Ipython4
hi,

I get this error experementing with Ipython4:

```
D:\WinPythonQt5\basedir34\build\winpython-3.4.3.amd64_build0\python-3.4.3.amd64\lib\site-packages\IPython\html.py:14: ShimWarning: The `IPython.html` package has been deprecated. You should import from `notebook` instead. `IPython.html.widgets` has moved to `ipywidgets`.
  "`IPython.html.widgets` has moved to `ipywidgets`.", ShimWarning)
```

``` python3
python-3.4.3.amd64\lib\site-packages\lmfit\ui\ipy_fitter.py in <module>()
     21 else:
     22     # as of IPython 3.x:
---> 23     from IPython.html.widgets import Dropdown
     24     from IPython.html.widgets import Button
     25     from IPython.html.widgets import Box

ImportError: No module named 'widgets'
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lmfit/ui/ipy_fitter.py`
Content:
```
1 import warnings
2 import numpy as np
3 
4 from ..model import Model
5 
6 from .basefitter import MPLFitter, _COMMON_DOC, _COMMON_EXAMPLES_DOC
7 
8 # Note: If IPython is not available of the version is < 2,
9 # this module will not be imported, and a different Fitter.
10 
11 import IPython
12 from IPython.display import display, clear_output
13 # Widgets were only experimental in IPython 2.x, but this does work there.
14 # Handle the change in naming from 2.x to 3.x.
15 IPY2 = IPython.release.version_info[0] == 2
16 if IPY2:
17     from IPython.html.widgets import DropdownWidget as Dropdown
18     from IPython.html.widgets import ButtonWidget as Button
19     from IPython.html.widgets import ContainerWidget as HBox
20     from IPython.html.widgets import FloatTextWidget as FloatText
21     from IPython.html.widgets import CheckboxWidget as Checkbox
22     class HBox(Box):
23         def __init__(*args, **kwargs):
24             self.add_class('hbox')
25             super(self, HBox).__init__(*args, **kwargs)
26 else:
27     # as of IPython 3.x:
28     from IPython.html.widgets import Dropdown
29     from IPython.html.widgets import Button
30     from IPython.html.widgets import HBox
31     from IPython.html.widgets import FloatText
32     from IPython.html.widgets import Checkbox
33 
34 
35 class ParameterWidgetGroup(object):
36     """Construct several widgets that together represent a Parameter.
37 
38     This will only be used if IPython is available."""
39     def __init__(self, par):
40         self.par = par
41 
42         # Define widgets.
43         self.value_text = FloatText(description=par.name,
44                                     min=self.par.min, max=self.par.max)
45         self.value_text.width = 100
46         self.min_text = FloatText(description='min', max=self.par.max)
47         self.min_text.width = 100
48         self.max_text = FloatText(description='max', min=self.par.min)
49         self.max_text.width = 100
50         self.min_checkbox = Checkbox(description='min')
51         self.max_checkbox = Checkbox(description='max')
52         self.vary_checkbox = Checkbox(description='vary')
53 
54         # Set widget values and visibility.
55         if par.value is not None:
56             self.value_text.value = self.par.value
57         min_unset = self.par.min is None or self.par.min == -np.inf
58         max_unset = self.par.max is None or self.par.max == np.inf
59         self.min_checkbox.value = not min_unset
60         self.min_text.visible = not min_unset
61         self.min_text.value = self.par.min
62         self.max_checkbox.value = not max_unset
63         self.max_text.visible = not max_unset
64         self.max_text.value = self.par.max
65         self.vary_checkbox.value = self.par.vary
66 
67         # Configure widgets to sync with par attributes.
68         self.value_text.on_trait_change(self._on_value_change, 'value')
69         self.min_text.on_trait_change(self._on_min_value_change, 'value')
70         self.max_text.on_trait_change(self._on_max_value_change, 'value')
71         self.min_checkbox.on_trait_change(self._on_min_checkbox_change,
72                                           'value')
73         self.max_checkbox.on_trait_change(self._on_max_checkbox_change,
74                                           'value')
75         self.vary_checkbox.on_trait_change(self._on_vary_change, 'value')
76 
77     def _on_value_change(self, name, value):
78         self.par.value = value
79 
80     def _on_min_checkbox_change(self, name, value):
81         self.min_text.visible = value
82         if value:
83             # -np.inf does not play well with a numerical text field,
84             # so set min to -1 if activated (and back to -inf if deactivated).
85             self.min_text.value = -1
86             self.par.min = self.min_text.value
87             self.value_text.min = self.min_text.value
88         else:
89             self.par.min = None
90 
91     def _on_max_checkbox_change(self, name, value):
92         self.max_text.visible = value
93         if value:
94             # np.inf does not play well with a numerical text field,
95             # so set max to 1 if activated (and back to inf if deactivated).
96             self.max_text.value = 1
97             self.par.max = self.max_text.value
98             self.value_text.max = self.max_text.value
99         else:
100             self.par.max = None
101 
102     def _on_min_value_change(self, name, value):
103         self.par.min = value
104         self.value_text.min = value
105         self.max_text.min = value
106 
107     def _on_max_value_change(self, name, value):
108         self.par.max = value
109         self.value_text.max = value
110         self.min_text.max = value
111 
112     def _on_vary_change(self, name, value):
113         self.par.vary = value
114         # self.value_text.disabled = not value
115 
116     def close(self):
117         # one convenience method to close (i.e., hide and disconnect) all
118         # widgets in this group
119         self.value_text.close()
120         self.min_text.close()
121         self.max_text.close()
122         self.vary_checkbox.close()
123         self.min_checkbox.close()
124         self.max_checkbox.close()
125 
126     def _repr_html_(self):
127         box = HBox()
128         box.children = [self.value_text, self.vary_checkbox,
129                         self.min_checkbox, self.min_text,
130                         self.max_checkbox, self.max_text]
131         display(box)
132 
133     # Make it easy to set the widget attributes directly.
134     @property
135     def value(self):
136         return self.value_text.value
137 
138     @value.setter
139     def value(self, value):
140         self.value_text.value = value
141 
142     @property
143     def vary(self):
144         return self.vary_checkbox.value
145 
146     @vary.setter
147     def vary(self, value):
148         self.vary_checkbox.value = value
149 
150     @property
151     def min(self):
152         return self.min_text.value
153 
154     @min.setter
155     def min(self, value):
156         self.min_text.value = value
157 
158     @property
159     def max(self):
160         return self.max_text.value
161 
162     @max.setter
163     def max(self, value):
164         self.max_text.value = value
165 
166     @property
167     def name(self):
168        return self.par.name
169 
170 
171 class NotebookFitter(MPLFitter):
172     __doc__ = _COMMON_DOC + """
173     If IPython is available, it uses the IPython notebook's rich display
174     to fit data interactively in a web-based GUI. The Parameters are
175     represented in a web-based form that is kept in sync with `current_params`.
176     All subclasses to Model, including user-defined ones, are shown in a
177     drop-down menu.
178 
179     Clicking the "Fit" button updates a plot, as above, and updates the
180     Parameters in the form to reflect the best fit.
181 
182     Parameters
183     ----------
184     data : array-like
185     model : lmfit.Model
186         optional initial Model to use, maybe be set or changed later
187     all_models : list
188         optional list of Models to populate drop-down menu, by default
189         all built-in and user-defined subclasses of Model are used
190 
191     Additional Parameters
192     ---------------------
193     axes_style : dictionary representing style keyword arguments to be
194         passed through to `Axes.set(...)`
195     data_style : dictionary representing style keyword arguments to be passed
196         through to the matplotlib `plot()` command the plots the data points
197     init_style : dictionary representing style keyword arguments to be passed
198         through to the matplotlib `plot()` command the plots the initial fit
199         line
200     best_style : dictionary representing style keyword arguments to be passed
201         through to the matplotlib `plot()` command the plots the best fit
202         line
203     **kwargs : independent variables or extra arguments, passed like `x=x`
204     """ + _COMMON_EXAMPLES_DOC
205     def __init__(self, data, model=None, all_models=None, axes_style={},
206                 data_style={}, init_style={}, best_style={}, **kwargs):
207         # Dropdown menu of all subclasses of Model, incl. user-defined.
208         self.models_menu = Dropdown()
209         # Dropbox API is very different between IPy 2.x and 3.x.
210         if IPY2:
211             if all_models is None:
212                 all_models = dict([(m.__name__, m) for m in Model.__subclasses__()])
213             self.models_menu.values = all_models
214         else:
215             if all_models is None:
216                 all_models = [(m.__name__, m) for m in Model.__subclasses__()]
217             self.models_menu.options = all_models
218         self.models_menu.on_trait_change(self._on_model_value_change,
219                                              'value')
220         # Button to trigger fitting.
221         self.fit_button = Button(description='Fit')
222         self.fit_button.on_click(self._on_fit_button_click)
223 
224         # Button to trigger guessing.
225         self.guess_button = Button(description='Auto-Guess')
226         self.guess_button.on_click(self._on_guess_button_click)
227 
228         # Parameter widgets are not built here. They are (re-)built when
229         # the model is (re-)set.
230         super(NotebookFitter, self).__init__(data, model, axes_style,
231                                              data_style, init_style,
232                                              best_style, **kwargs)
233 
234     def _repr_html_(self):
235         display(self.models_menu)
236         button_box = HBox()
237         button_box.children = [self.fit_button, self.guess_button]
238         display(button_box)
239         for pw in self.param_widgets:
240             display(pw)
241         self.plot()
242 
243     def guess(self):
244         guessing_successful = super(NotebookFitter, self).guess()
245         self.guess_button.disabled = not guessing_successful
246 
247     def _finalize_model(self, value):
248         first_run = not hasattr(self, 'param_widgets')
249         if not first_run:
250             # Remove all Parameter widgets, and replace them with widgets
251             # for the new model.
252             for pw in self.param_widgets:
253                 pw.close()
254         self.models_menu.value = value
255         self.param_widgets = [ParameterWidgetGroup(p)
256                               for _, p in self._current_params.items()]
257         if not first_run:
258             for pw in self.param_widgets:
259                 display(pw)
260 
261     def _finalize_params(self):
262         for pw in self.param_widgets:
263             pw.value = self._current_params[pw.name].value
264             pw.min = self._current_params[pw.name].min
265             pw.max = self._current_params[pw.name].max
266             pw.vary = self._current_params[pw.name].vary
267 
268     def plot(self):
269         clear_output(wait=True)
270         super(NotebookFitter, self).plot()
271 
272     def fit(self):
273         super(NotebookFitter, self).fit()
274         self.plot()
275
```
--- 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/lmfit/ui/ipy_fitter.py b/lmfit/ui/ipy_fitter.py
--- a/lmfit/ui/ipy_fitter.py
+++ b/lmfit/ui/ipy_fitter.py
@@ -13,6 +13,7 @@
 # Widgets were only experimental in IPython 2.x, but this does work there.
 # Handle the change in naming from 2.x to 3.x.
 IPY2 = IPython.release.version_info[0] == 2
+IPY3 = IPython.release.version_info[0] == 3
 if IPY2:
     from IPython.html.widgets import DropdownWidget as Dropdown
     from IPython.html.widgets import ButtonWidget as Button
@@ -23,13 +24,20 @@
         def __init__(*args, **kwargs):
             self.add_class('hbox')
             super(self, HBox).__init__(*args, **kwargs)
-else:
+elif IPY3:
     # as of IPython 3.x:
     from IPython.html.widgets import Dropdown
     from IPython.html.widgets import Button
     from IPython.html.widgets import HBox
     from IPython.html.widgets import FloatText
     from IPython.html.widgets import Checkbox
+else:
+    # as of IPython 4.x+:
+    from ipywidgets import Dropdown
+    from ipywidgets import Button
+    from ipywidgets import Box
+    from ipywidgets import FloatText
+    from ipywidgets import Checkbox
 
 
 class ParameterWidgetGroup(object):

{"golden_diff": "diff --git a/lmfit/ui/ipy_fitter.py b/lmfit/ui/ipy_fitter.py\n--- a/lmfit/ui/ipy_fitter.py\n+++ b/lmfit/ui/ipy_fitter.py\n@@ -13,6 +13,7 @@\n # Widgets were only experimental in IPython 2.x, but this does work there.\n # Handle the change in naming from 2.x to 3.x.\n IPY2 = IPython.release.version_info[0] == 2\n+IPY3 = IPython.release.version_info[0] == 3\n if IPY2:\n     from IPython.html.widgets import DropdownWidget as Dropdown\n     from IPython.html.widgets import ButtonWidget as Button\n@@ -23,13 +24,20 @@\n         def __init__(*args, **kwargs):\n             self.add_class('hbox')\n             super(self, HBox).__init__(*args, **kwargs)\n-else:\n+elif IPY3:\n     # as of IPython 3.x:\n     from IPython.html.widgets import Dropdown\n     from IPython.html.widgets import Button\n     from IPython.html.widgets import HBox\n     from IPython.html.widgets import FloatText\n     from IPython.html.widgets import Checkbox\n+else:\n+    # as of IPython 4.x+:\n+    from ipywidgets import Dropdown\n+    from ipywidgets import Button\n+    from ipywidgets import Box\n+    from ipywidgets import FloatText\n+    from ipywidgets import Checkbox\n \n \n class ParameterWidgetGroup(object):\n", "issue": "compatibility issue with Ipython4\nhi,\n\nI get this error experementing with Ipython4:\n\n```\nD:\\WinPythonQt5\\basedir34\\build\\winpython-3.4.3.amd64_build0\\python-3.4.3.amd64\\lib\\site-packages\\IPython\\html.py:14: ShimWarning: The `IPython.html` package has been deprecated. You should import from `notebook` instead. `IPython.html.widgets` has moved to `ipywidgets`.\n  \"`IPython.html.widgets` has moved to `ipywidgets`.\", ShimWarning)\n```\n\n``` python3\npython-3.4.3.amd64\\lib\\site-packages\\lmfit\\ui\\ipy_fitter.py in <module>()\n     21 else:\n     22     # as of IPython 3.x:\n---> 23     from IPython.html.widgets import Dropdown\n     24     from IPython.html.widgets import Button\n     25     from IPython.html.widgets import Box\n\nImportError: No module named 'widgets'\n```\n\n", "before_files": [{"content": "import warnings\nimport numpy as np\n\nfrom ..model import Model\n\nfrom .basefitter import MPLFitter, _COMMON_DOC, _COMMON_EXAMPLES_DOC\n\n# Note: If IPython is not available of the version is < 2,\n# this module will not be imported, and a different Fitter.\n\nimport IPython\nfrom IPython.display import display, clear_output\n# Widgets were only experimental in IPython 2.x, but this does work there.\n# Handle the change in naming from 2.x to 3.x.\nIPY2 = IPython.release.version_info[0] == 2\nif IPY2:\n    from IPython.html.widgets import DropdownWidget as Dropdown\n    from IPython.html.widgets import ButtonWidget as Button\n    from IPython.html.widgets import ContainerWidget as HBox\n    from IPython.html.widgets import FloatTextWidget as FloatText\n    from IPython.html.widgets import CheckboxWidget as Checkbox\n    class HBox(Box):\n        def __init__(*args, **kwargs):\n            self.add_class('hbox')\n            super(self, HBox).__init__(*args, **kwargs)\nelse:\n    # as of IPython 3.x:\n    from IPython.html.widgets import Dropdown\n    from IPython.html.widgets import Button\n    from IPython.html.widgets import HBox\n    from IPython.html.widgets import FloatText\n    from IPython.html.widgets import Checkbox\n\n\nclass ParameterWidgetGroup(object):\n    \"\"\"Construct several widgets that together represent a Parameter.\n\n    This will only be used if IPython is available.\"\"\"\n    def __init__(self, par):\n        self.par = par\n\n        # Define widgets.\n        self.value_text = FloatText(description=par.name,\n                                    min=self.par.min, max=self.par.max)\n        self.value_text.width = 100\n        self.min_text = FloatText(description='min', max=self.par.max)\n        self.min_text.width = 100\n        self.max_text = FloatText(description='max', min=self.par.min)\n        self.max_text.width = 100\n        self.min_checkbox = Checkbox(description='min')\n        self.max_checkbox = Checkbox(description='max')\n        self.vary_checkbox = Checkbox(description='vary')\n\n        # Set widget values and visibility.\n        if par.value is not None:\n            self.value_text.value = self.par.value\n        min_unset = self.par.min is None or self.par.min == -np.inf\n        max_unset = self.par.max is None or self.par.max == np.inf\n        self.min_checkbox.value = not min_unset\n        self.min_text.visible = not min_unset\n        self.min_text.value = self.par.min\n        self.max_checkbox.value = not max_unset\n        self.max_text.visible = not max_unset\n        self.max_text.value = self.par.max\n        self.vary_checkbox.value = self.par.vary\n\n        # Configure widgets to sync with par attributes.\n        self.value_text.on_trait_change(self._on_value_change, 'value')\n        self.min_text.on_trait_change(self._on_min_value_change, 'value')\n        self.max_text.on_trait_change(self._on_max_value_change, 'value')\n        self.min_checkbox.on_trait_change(self._on_min_checkbox_change,\n                                          'value')\n        self.max_checkbox.on_trait_change(self._on_max_checkbox_change,\n                                          'value')\n        self.vary_checkbox.on_trait_change(self._on_vary_change, 'value')\n\n    def _on_value_change(self, name, value):\n        self.par.value = value\n\n    def _on_min_checkbox_change(self, name, value):\n        self.min_text.visible = value\n        if value:\n            # -np.inf does not play well with a numerical text field,\n            # so set min to -1 if activated (and back to -inf if deactivated).\n            self.min_text.value = -1\n            self.par.min = self.min_text.value\n            self.value_text.min = self.min_text.value\n        else:\n            self.par.min = None\n\n    def _on_max_checkbox_change(self, name, value):\n        self.max_text.visible = value\n        if value:\n            # np.inf does not play well with a numerical text field,\n            # so set max to 1 if activated (and back to inf if deactivated).\n            self.max_text.value = 1\n            self.par.max = self.max_text.value\n            self.value_text.max = self.max_text.value\n        else:\n            self.par.max = None\n\n    def _on_min_value_change(self, name, value):\n        self.par.min = value\n        self.value_text.min = value\n        self.max_text.min = value\n\n    def _on_max_value_change(self, name, value):\n        self.par.max = value\n        self.value_text.max = value\n        self.min_text.max = value\n\n    def _on_vary_change(self, name, value):\n        self.par.vary = value\n        # self.value_text.disabled = not value\n\n    def close(self):\n        # one convenience method to close (i.e., hide and disconnect) all\n        # widgets in this group\n        self.value_text.close()\n        self.min_text.close()\n        self.max_text.close()\n        self.vary_checkbox.close()\n        self.min_checkbox.close()\n        self.max_checkbox.close()\n\n    def _repr_html_(self):\n        box = HBox()\n        box.children = [self.value_text, self.vary_checkbox,\n                        self.min_checkbox, self.min_text,\n                        self.max_checkbox, self.max_text]\n        display(box)\n\n    # Make it easy to set the widget attributes directly.\n    @property\n    def value(self):\n        return self.value_text.value\n\n    @value.setter\n    def value(self, value):\n        self.value_text.value = value\n\n    @property\n    def vary(self):\n        return self.vary_checkbox.value\n\n    @vary.setter\n    def vary(self, value):\n        self.vary_checkbox.value = value\n\n    @property\n    def min(self):\n        return self.min_text.value\n\n    @min.setter\n    def min(self, value):\n        self.min_text.value = value\n\n    @property\n    def max(self):\n        return self.max_text.value\n\n    @max.setter\n    def max(self, value):\n        self.max_text.value = value\n\n    @property\n    def name(self):\n       return self.par.name\n\n\nclass NotebookFitter(MPLFitter):\n    __doc__ = _COMMON_DOC + \"\"\"\n    If IPython is available, it uses the IPython notebook's rich display\n    to fit data interactively in a web-based GUI. The Parameters are\n    represented in a web-based form that is kept in sync with `current_params`.\n    All subclasses to Model, including user-defined ones, are shown in a\n    drop-down menu.\n\n    Clicking the \"Fit\" button updates a plot, as above, and updates the\n    Parameters in the form to reflect the best fit.\n\n    Parameters\n    ----------\n    data : array-like\n    model : lmfit.Model\n        optional initial Model to use, maybe be set or changed later\n    all_models : list\n        optional list of Models to populate drop-down menu, by default\n        all built-in and user-defined subclasses of Model are used\n\n    Additional Parameters\n    ---------------------\n    axes_style : dictionary representing style keyword arguments to be\n        passed through to `Axes.set(...)`\n    data_style : dictionary representing style keyword arguments to be passed\n        through to the matplotlib `plot()` command the plots the data points\n    init_style : dictionary representing style keyword arguments to be passed\n        through to the matplotlib `plot()` command the plots the initial fit\n        line\n    best_style : dictionary representing style keyword arguments to be passed\n        through to the matplotlib `plot()` command the plots the best fit\n        line\n    **kwargs : independent variables or extra arguments, passed like `x=x`\n    \"\"\" + _COMMON_EXAMPLES_DOC\n    def __init__(self, data, model=None, all_models=None, axes_style={},\n                data_style={}, init_style={}, best_style={}, **kwargs):\n        # Dropdown menu of all subclasses of Model, incl. user-defined.\n        self.models_menu = Dropdown()\n        # Dropbox API is very different between IPy 2.x and 3.x.\n        if IPY2:\n            if all_models is None:\n                all_models = dict([(m.__name__, m) for m in Model.__subclasses__()])\n            self.models_menu.values = all_models\n        else:\n            if all_models is None:\n                all_models = [(m.__name__, m) for m in Model.__subclasses__()]\n            self.models_menu.options = all_models\n        self.models_menu.on_trait_change(self._on_model_value_change,\n                                             'value')\n        # Button to trigger fitting.\n        self.fit_button = Button(description='Fit')\n        self.fit_button.on_click(self._on_fit_button_click)\n\n        # Button to trigger guessing.\n        self.guess_button = Button(description='Auto-Guess')\n        self.guess_button.on_click(self._on_guess_button_click)\n\n        # Parameter widgets are not built here. They are (re-)built when\n        # the model is (re-)set.\n        super(NotebookFitter, self).__init__(data, model, axes_style,\n                                             data_style, init_style,\n                                             best_style, **kwargs)\n\n    def _repr_html_(self):\n        display(self.models_menu)\n        button_box = HBox()\n        button_box.children = [self.fit_button, self.guess_button]\n        display(button_box)\n        for pw in self.param_widgets:\n            display(pw)\n        self.plot()\n\n    def guess(self):\n        guessing_successful = super(NotebookFitter, self).guess()\n        self.guess_button.disabled = not guessing_successful\n\n    def _finalize_model(self, value):\n        first_run = not hasattr(self, 'param_widgets')\n        if not first_run:\n            # Remove all Parameter widgets, and replace them with widgets\n            # for the new model.\n            for pw in self.param_widgets:\n                pw.close()\n        self.models_menu.value = value\n        self.param_widgets = [ParameterWidgetGroup(p)\n                              for _, p in self._current_params.items()]\n        if not first_run:\n            for pw in self.param_widgets:\n                display(pw)\n\n    def _finalize_params(self):\n        for pw in self.param_widgets:\n            pw.value = self._current_params[pw.name].value\n            pw.min = self._current_params[pw.name].min\n            pw.max = self._current_params[pw.name].max\n            pw.vary = self._current_params[pw.name].vary\n\n    def plot(self):\n        clear_output(wait=True)\n        super(NotebookFitter, self).plot()\n\n    def fit(self):\n        super(NotebookFitter, self).fit()\n        self.plot()\n", "path": "lmfit/ui/ipy_fitter.py"}], "after_files": [{"content": "import warnings\nimport numpy as np\n\nfrom ..model import Model\n\nfrom .basefitter import MPLFitter, _COMMON_DOC, _COMMON_EXAMPLES_DOC\n\n# Note: If IPython is not available of the version is < 2,\n# this module will not be imported, and a different Fitter.\n\nimport IPython\nfrom IPython.display import display, clear_output\n# Widgets were only experimental in IPython 2.x, but this does work there.\n# Handle the change in naming from 2.x to 3.x.\nIPY2 = IPython.release.version_info[0] == 2\nIPY3 = IPython.release.version_info[0] == 3\nif IPY2:\n    from IPython.html.widgets import DropdownWidget as Dropdown\n    from IPython.html.widgets import ButtonWidget as Button\n    from IPython.html.widgets import ContainerWidget as HBox\n    from IPython.html.widgets import FloatTextWidget as FloatText\n    from IPython.html.widgets import CheckboxWidget as Checkbox\n    class HBox(Box):\n        def __init__(*args, **kwargs):\n            self.add_class('hbox')\n            super(self, HBox).__init__(*args, **kwargs)\nelif IPY3:\n    # as of IPython 3.x:\n    from IPython.html.widgets import Dropdown\n    from IPython.html.widgets import Button\n    from IPython.html.widgets import HBox\n    from IPython.html.widgets import FloatText\n    from IPython.html.widgets import Checkbox\nelse:\n    # as of IPython 4.x+:\n    from ipywidgets import Dropdown\n    from ipywidgets import Button\n    from ipywidgets import Box\n    from ipywidgets import FloatText\n    from ipywidgets import Checkbox\n\n\nclass ParameterWidgetGroup(object):\n    \"\"\"Construct several widgets that together represent a Parameter.\n\n    This will only be used if IPython is available.\"\"\"\n    def __init__(self, par):\n        self.par = par\n\n        # Define widgets.\n        self.value_text = FloatText(description=par.name,\n                                    min=self.par.min, max=self.par.max)\n        self.value_text.width = 100\n        self.min_text = FloatText(description='min', max=self.par.max)\n        self.min_text.width = 100\n        self.max_text = FloatText(description='max', min=self.par.min)\n        self.max_text.width = 100\n        self.min_checkbox = Checkbox(description='min')\n        self.max_checkbox = Checkbox(description='max')\n        self.vary_checkbox = Checkbox(description='vary')\n\n        # Set widget values and visibility.\n        if par.value is not None:\n            self.value_text.value = self.par.value\n        min_unset = self.par.min is None or self.par.min == -np.inf\n        max_unset = self.par.max is None or self.par.max == np.inf\n        self.min_checkbox.value = not min_unset\n        self.min_text.visible = not min_unset\n        self.min_text.value = self.par.min\n        self.max_checkbox.value = not max_unset\n        self.max_text.visible = not max_unset\n        self.max_text.value = self.par.max\n        self.vary_checkbox.value = self.par.vary\n\n        # Configure widgets to sync with par attributes.\n        self.value_text.on_trait_change(self._on_value_change, 'value')\n        self.min_text.on_trait_change(self._on_min_value_change, 'value')\n        self.max_text.on_trait_change(self._on_max_value_change, 'value')\n        self.min_checkbox.on_trait_change(self._on_min_checkbox_change,\n                                          'value')\n        self.max_checkbox.on_trait_change(self._on_max_checkbox_change,\n                                          'value')\n        self.vary_checkbox.on_trait_change(self._on_vary_change, 'value')\n\n    def _on_value_change(self, name, value):\n        self.par.value = value\n\n    def _on_min_checkbox_change(self, name, value):\n        self.min_text.visible = value\n        if value:\n            # -np.inf does not play well with a numerical text field,\n            # so set min to -1 if activated (and back to -inf if deactivated).\n            self.min_text.value = -1\n            self.par.min = self.min_text.value\n            self.value_text.min = self.min_text.value\n        else:\n            self.par.min = None\n\n    def _on_max_checkbox_change(self, name, value):\n        self.max_text.visible = value\n        if value:\n            # np.inf does not play well with a numerical text field,\n            # so set max to 1 if activated (and back to inf if deactivated).\n            self.max_text.value = 1\n            self.par.max = self.max_text.value\n            self.value_text.max = self.max_text.value\n        else:\n            self.par.max = None\n\n    def _on_min_value_change(self, name, value):\n        self.par.min = value\n        self.value_text.min = value\n        self.max_text.min = value\n\n    def _on_max_value_change(self, name, value):\n        self.par.max = value\n        self.value_text.max = value\n        self.min_text.max = value\n\n    def _on_vary_change(self, name, value):\n        self.par.vary = value\n        # self.value_text.disabled = not value\n\n    def close(self):\n        # one convenience method to close (i.e., hide and disconnect) all\n        # widgets in this group\n        self.value_text.close()\n        self.min_text.close()\n        self.max_text.close()\n        self.vary_checkbox.close()\n        self.min_checkbox.close()\n        self.max_checkbox.close()\n\n    def _repr_html_(self):\n        box = HBox()\n        box.children = [self.value_text, self.vary_checkbox,\n                        self.min_checkbox, self.min_text,\n                        self.max_checkbox, self.max_text]\n        display(box)\n\n    # Make it easy to set the widget attributes directly.\n    @property\n    def value(self):\n        return self.value_text.value\n\n    @value.setter\n    def value(self, value):\n        self.value_text.value = value\n\n    @property\n    def vary(self):\n        return self.vary_checkbox.value\n\n    @vary.setter\n    def vary(self, value):\n        self.vary_checkbox.value = value\n\n    @property\n    def min(self):\n        return self.min_text.value\n\n    @min.setter\n    def min(self, value):\n        self.min_text.value = value\n\n    @property\n    def max(self):\n        return self.max_text.value\n\n    @max.setter\n    def max(self, value):\n        self.max_text.value = value\n\n    @property\n    def name(self):\n       return self.par.name\n\n\nclass NotebookFitter(MPLFitter):\n    __doc__ = _COMMON_DOC + \"\"\"\n    If IPython is available, it uses the IPython notebook's rich display\n    to fit data interactively in a web-based GUI. The Parameters are\n    represented in a web-based form that is kept in sync with `current_params`.\n    All subclasses to Model, including user-defined ones, are shown in a\n    drop-down menu.\n\n    Clicking the \"Fit\" button updates a plot, as above, and updates the\n    Parameters in the form to reflect the best fit.\n\n    Parameters\n    ----------\n    data : array-like\n    model : lmfit.Model\n        optional initial Model to use, maybe be set or changed later\n    all_models : list\n        optional list of Models to populate drop-down menu, by default\n        all built-in and user-defined subclasses of Model are used\n\n    Additional Parameters\n    ---------------------\n    axes_style : dictionary representing style keyword arguments to be\n        passed through to `Axes.set(...)`\n    data_style : dictionary representing style keyword arguments to be passed\n        through to the matplotlib `plot()` command the plots the data points\n    init_style : dictionary representing style keyword arguments to be passed\n        through to the matplotlib `plot()` command the plots the initial fit\n        line\n    best_style : dictionary representing style keyword arguments to be passed\n        through to the matplotlib `plot()` command the plots the best fit\n        line\n    **kwargs : independent variables or extra arguments, passed like `x=x`\n    \"\"\" + _COMMON_EXAMPLES_DOC\n    def __init__(self, data, model=None, all_models=None, axes_style={},\n                data_style={}, init_style={}, best_style={}, **kwargs):\n        # Dropdown menu of all subclasses of Model, incl. user-defined.\n        self.models_menu = Dropdown()\n        # Dropbox API is very different between IPy 2.x and 3.x.\n        if IPY2:\n            if all_models is None:\n                all_models = dict([(m.__name__, m) for m in Model.__subclasses__()])\n            self.models_menu.values = all_models\n        else:\n            if all_models is None:\n                all_models = [(m.__name__, m) for m in Model.__subclasses__()]\n            self.models_menu.options = all_models\n        self.models_menu.on_trait_change(self._on_model_value_change,\n                                             'value')\n        # Button to trigger fitting.\n        self.fit_button = Button(description='Fit')\n        self.fit_button.on_click(self._on_fit_button_click)\n\n        # Button to trigger guessing.\n        self.guess_button = Button(description='Auto-Guess')\n        self.guess_button.on_click(self._on_guess_button_click)\n\n        # Parameter widgets are not built here. They are (re-)built when\n        # the model is (re-)set.\n        super(NotebookFitter, self).__init__(data, model, axes_style,\n                                             data_style, init_style,\n                                             best_style, **kwargs)\n\n    def _repr_html_(self):\n        display(self.models_menu)\n        button_box = HBox()\n        button_box.children = [self.fit_button, self.guess_button]\n        display(button_box)\n        for pw in self.param_widgets:\n            display(pw)\n        self.plot()\n\n    def guess(self):\n        guessing_successful = super(NotebookFitter, self).guess()\n        self.guess_button.disabled = not guessing_successful\n\n    def _finalize_model(self, value):\n        first_run = not hasattr(self, 'param_widgets')\n        if not first_run:\n            # Remove all Parameter widgets, and replace them with widgets\n            # for the new model.\n            for pw in self.param_widgets:\n                pw.close()\n        self.models_menu.value = value\n        self.param_widgets = [ParameterWidgetGroup(p)\n                              for _, p in self._current_params.items()]\n        if not first_run:\n            for pw in self.param_widgets:\n                display(pw)\n\n    def _finalize_params(self):\n        for pw in self.param_widgets:\n            pw.value = self._current_params[pw.name].value\n            pw.min = self._current_params[pw.name].min\n            pw.max = self._current_params[pw.name].max\n            pw.vary = self._current_params[pw.name].vary\n\n    def plot(self):\n        clear_output(wait=True)\n        super(NotebookFitter, self).plot()\n\n    def fit(self):\n        super(NotebookFitter, self).fit()\n        self.plot()\n", "path": "lmfit/ui/ipy_fitter.py"}]}