We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Import fails when run using a Bokeh server
**Description of bug**
The import of `arviz` errors when running with a [Bokeh server](https://docs.bokeh.org/en/latest/docs/user_guide/server.html).

The resulting error is:
```
output_notebook.__doc__ += "\n\n" + _copy_docstring("bokeh.plotting", "output_notebook") Traceback (most recent call last):
  File "/Users/golmschenk/Code/ramjet/venv/lib/python3.7/site-packages/bokeh/application/handlers/code_runner.py", line 197, in run
    exec(self._code, module.__dict__)
  File "/Users/golmschenk/Code/ramjet/minimal_example/main.py", line 1, in <module>
    import arviz
  File "/Users/golmschenk/Code/ramjet/venv/lib/python3.7/site-packages/arviz/__init__.py", line 31, in <module>
    from .plots import backends
  File "/Users/golmschenk/Code/ramjet/venv/lib/python3.7/site-packages/arviz/plots/backends/__init__.py", line 195, in <module>
    output_notebook.__doc__ += "\n\n" + _copy_docstring("bokeh.plotting", "output_notebook")
TypeError: can only concatenate str (not "NoneType") to str
```


**To Reproduce**

1. Have `bokeh` and `arviz` installed.
2. Create a Python file which only contains `import arviz`.
3. From the terminal, run `bokeh serve <file_name>.py`.
4. Open the localhost server link in a browser.

**Expected behavior**
`arviz` should be imported without error.

**Additional context**
`arviz` appears to be setting a docstring based off `_copy_docstring("bokeh.plotting", "output_notebook")`, however, in this context, `_copy_docstring("bokeh.plotting", "output_notebook")` is `None`.

Package versions:
```
arviz==0.7.0
bokeh==2.0.1
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `arviz/plots/backends/__init__.py`
Content:
```
1 # pylint: disable=no-member,invalid-name,redefined-outer-name
2 """ArviZ plotting backends."""
3 import re
4 import numpy as np
5 from pandas import DataFrame
6 
7 from ...rcparams import rcParams
8 
9 
10 def to_cds(
11     data,
12     var_names=None,
13     groups=None,
14     dimensions=None,
15     group_info=True,
16     var_name_format=None,
17     index_origin=None,
18 ):
19     """Transform data to ColumnDataSource (CDS) compatible with Bokeh.
20 
21     Uses `_ARVIZ_GROUP_` and `_ARVIZ_CDS_SELECTION_`to separate var_name
22     from group and dimensions in CDS columns.
23 
24     Parameters
25     ----------
26     data : obj
27         Any object that can be converted to an az.InferenceData object
28         Refer to documentation of az.convert_to_inference_data for details
29     var_names : str or list of str, optional
30         Variables to be processed, if None all variables are processed.
31     groups : str or list of str, optional
32         Select groups for CDS. Default groups are {"posterior_groups", "prior_groups",
33         "posterior_groups_warmup"}
34             - posterior_groups: posterior, posterior_predictive, sample_stats
35             - prior_groups: prior, prior_predictive, sample_stats_prior
36             - posterior_groups_warmup: warmup_posterior, warmup_posterior_predictive,
37                                        warmup_sample_stats
38     ignore_groups : str or list of str, optional
39         Ignore specific groups from CDS.
40     dimension : str, or list of str, optional
41         Select dimensions along to slice the data. By default uses ("chain", "draw").
42     group_info : bool
43         Add group info for `var_name_format`
44     var_name_format : str or tuple of tuple of string, optional
45         Select column name format for non-scalar input.
46         Predefined options are {"brackets", "underscore", "cds"}
47             "brackets":
48                 - add_group_info == False: theta[0,0]
49                 - add_group_info == True: theta_posterior[0,0]
50             "underscore":
51                 - add_group_info == False: theta_0_0
52                 - add_group_info == True: theta_posterior_0_0_
53             "cds":
54                 - add_group_info == False: theta_ARVIZ_CDS_SELECTION_0_0
55                 - add_group_info == True: theta_ARVIZ_GROUP_posterior__ARVIZ_CDS_SELECTION_0_0
56             tuple:
57                 Structure:
58                     tuple: (dim_info, group_info)
59                         dim_info: (str: `.join` separator,
60                                    str: dim_separator_start,
61                                    str: dim_separator_end)
62                         group_info: (str: group separator start, str: group separator end)
63                 Example: ((",", "[", "]"), ("_", ""))
64                     - add_group_info == False: theta[0,0]
65                     - add_group_info == True: theta_posterior[0,0]
66     index_origin : int, optional
67         Start parameter indices from `index_origin`. Either 0 or 1.
68 
69     Returns
70     -------
71     bokeh.models.ColumnDataSource object
72     """
73     from ...utils import flatten_inference_data_to_dict
74 
75     if var_name_format is None:
76         var_name_format = "cds"
77 
78     cds_dict = flatten_inference_data_to_dict(
79         data=data,
80         var_names=var_names,
81         groups=groups,
82         dimensions=dimensions,
83         group_info=group_info,
84         index_origin=index_origin,
85         var_name_format=var_name_format,
86     )
87     cds_data = ColumnDataSource(DataFrame.from_dict(cds_dict, orient="columns"))
88     return cds_data
89 
90 
91 def output_notebook(*args, **kwargs):
92     """Wrap bokeh.plotting.output_notebook."""
93     import bokeh.plotting as bkp
94 
95     return bkp.output_notebook(*args, **kwargs)
96 
97 
98 def output_file(*args, **kwargs):
99     """Wrap bokeh.plotting.output_file."""
100     import bokeh.plotting as bkp
101 
102     return bkp.output_file(*args, **kwargs)
103 
104 
105 def ColumnDataSource(*args, **kwargs):
106     """Wrap bokeh.models.ColumnDataSource."""
107     from bokeh.models import ColumnDataSource
108 
109     return ColumnDataSource(*args, **kwargs)
110 
111 
112 def create_layout(ax, force_layout=False):
113     """Transform bokeh array of figures to layout."""
114     ax = np.atleast_2d(ax)
115     subplot_order = rcParams["plot.bokeh.layout.order"]
116     if force_layout:
117         from bokeh.layouts import gridplot as layout
118 
119         ax = ax.tolist()
120         layout_args = {
121             "sizing_mode": rcParams["plot.bokeh.layout.sizing_mode"],
122             "toolbar_location": rcParams["plot.bokeh.layout.toolbar_location"],
123         }
124     elif any(item in subplot_order for item in ("row", "column")):
125         # check number of rows
126         match = re.match(r"(\d*)(row|column)", subplot_order)
127         n = int(match.group(1)) if match.group(1) is not None else 1
128         subplot_order = match.group(2)
129         # set up 1D list of axes
130         ax = [item for item in ax.ravel().tolist() if item is not None]
131         layout_args = {"sizing_mode": rcParams["plot.bokeh.layout.sizing_mode"]}
132         if subplot_order == "row" and n == 1:
133             from bokeh.layouts import row as layout
134         elif subplot_order == "column" and n == 1:
135             from bokeh.layouts import column as layout
136         else:
137             from bokeh.layouts import layout
138 
139         if n != 1:
140             ax = np.array(ax + [None for _ in range(int(np.ceil(len(ax) / n)) - len(ax))])
141             if subplot_order == "row":
142                 ax = ax.reshape(n, -1)
143             else:
144                 ax = ax.reshape(-1, n)
145             ax = ax.tolist()
146     else:
147         if subplot_order in ("square", "square_trimmed"):
148             ax = [item for item in ax.ravel().tolist() if item is not None]
149             n = int(np.ceil(len(ax) ** 0.5))
150             ax = ax + [None for _ in range(n ** 2 - len(ax))]
151             ax = np.array(ax).reshape(n, n)
152         ax = ax.tolist()
153         if (subplot_order == "square_trimmed") and any(
154             all(item is None for item in row) for row in ax
155         ):
156             from bokeh.layouts import layout
157 
158             ax = [row for row in ax if not all(item is None for item in row)]
159             layout_args = {"sizing_mode": rcParams["plot.bokeh.layout.sizing_mode"]}
160         else:
161             from bokeh.layouts import gridplot as layout
162 
163             layout_args = {
164                 "sizing_mode": rcParams["plot.bokeh.layout.sizing_mode"],
165                 "toolbar_location": rcParams["plot.bokeh.layout.toolbar_location"],
166             }
167     # ignore "fixed" sizing_mode without explicit width and height
168     if layout_args.get("sizing_mode", "") == "fixed":
169         layout_args.pop("sizing_mode")
170     return layout(ax, **layout_args)
171 
172 
173 def show_layout(ax, show=True, force_layout=False):
174     """Create a layout and call bokeh show."""
175     if show is None:
176         show = rcParams["plot.bokeh.show"]
177     if show:
178         import bokeh.plotting as bkp
179 
180         layout = create_layout(ax, force_layout=force_layout)
181         bkp.show(layout)
182 
183 
184 def _copy_docstring(lib, function):
185     """Extract docstring from function."""
186     import importlib
187 
188     try:
189         module = importlib.import_module(lib)
190         func = getattr(module, function)
191         doc = func.__doc__
192     except ImportError:
193         doc = "Failed to import function {} from {}".format(function, lib)
194 
195     return doc
196 
197 
198 output_notebook.__doc__ += "\n\n" + _copy_docstring("bokeh.plotting", "output_notebook")
199 output_file.__doc__ += "\n\n" + _copy_docstring("bokeh.plotting", "output_file")
200 ColumnDataSource.__doc__ += "\n\n" + _copy_docstring("bokeh.models", "ColumnDataSource")
201
```
--- 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/arviz/plots/backends/__init__.py b/arviz/plots/backends/__init__.py
--- a/arviz/plots/backends/__init__.py
+++ b/arviz/plots/backends/__init__.py
@@ -192,6 +192,8 @@
     except ImportError:
         doc = "Failed to import function {} from {}".format(function, lib)
 
+    if not isinstance(doc, str):
+        doc = ""
     return doc

{"golden_diff": "diff --git a/arviz/plots/backends/__init__.py b/arviz/plots/backends/__init__.py\n--- a/arviz/plots/backends/__init__.py\n+++ b/arviz/plots/backends/__init__.py\n@@ -192,6 +192,8 @@\n     except ImportError:\n         doc = \"Failed to import function {} from {}\".format(function, lib)\n \n+    if not isinstance(doc, str):\n+        doc = \"\"\n     return doc\n", "issue": "Import fails when run using a Bokeh server\n**Description of bug**\r\nThe import of `arviz` errors when running with a [Bokeh server](https://docs.bokeh.org/en/latest/docs/user_guide/server.html).\r\n\r\nThe resulting error is:\r\n```\r\noutput_notebook.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.plotting\", \"output_notebook\") Traceback (most recent call last):\r\n  File \"/Users/golmschenk/Code/ramjet/venv/lib/python3.7/site-packages/bokeh/application/handlers/code_runner.py\", line 197, in run\r\n    exec(self._code, module.__dict__)\r\n  File \"/Users/golmschenk/Code/ramjet/minimal_example/main.py\", line 1, in <module>\r\n    import arviz\r\n  File \"/Users/golmschenk/Code/ramjet/venv/lib/python3.7/site-packages/arviz/__init__.py\", line 31, in <module>\r\n    from .plots import backends\r\n  File \"/Users/golmschenk/Code/ramjet/venv/lib/python3.7/site-packages/arviz/plots/backends/__init__.py\", line 195, in <module>\r\n    output_notebook.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.plotting\", \"output_notebook\")\r\nTypeError: can only concatenate str (not \"NoneType\") to str\r\n```\r\n\r\n\r\n**To Reproduce**\r\n\r\n1. Have `bokeh` and `arviz` installed.\r\n2. Create a Python file which only contains `import arviz`.\r\n3. From the terminal, run `bokeh serve <file_name>.py`.\r\n4. Open the localhost server link in a browser.\r\n\r\n**Expected behavior**\r\n`arviz` should be imported without error.\r\n\r\n**Additional context**\r\n`arviz` appears to be setting a docstring based off `_copy_docstring(\"bokeh.plotting\", \"output_notebook\")`, however, in this context, `_copy_docstring(\"bokeh.plotting\", \"output_notebook\")` is `None`.\r\n\r\nPackage versions:\r\n```\r\narviz==0.7.0\r\nbokeh==2.0.1\r\n```\r\n\n", "before_files": [{"content": "# pylint: disable=no-member,invalid-name,redefined-outer-name\n\"\"\"ArviZ plotting backends.\"\"\"\nimport re\nimport numpy as np\nfrom pandas import DataFrame\n\nfrom ...rcparams import rcParams\n\n\ndef to_cds(\n    data,\n    var_names=None,\n    groups=None,\n    dimensions=None,\n    group_info=True,\n    var_name_format=None,\n    index_origin=None,\n):\n    \"\"\"Transform data to ColumnDataSource (CDS) compatible with Bokeh.\n\n    Uses `_ARVIZ_GROUP_` and `_ARVIZ_CDS_SELECTION_`to separate var_name\n    from group and dimensions in CDS columns.\n\n    Parameters\n    ----------\n    data : obj\n        Any object that can be converted to an az.InferenceData object\n        Refer to documentation of az.convert_to_inference_data for details\n    var_names : str or list of str, optional\n        Variables to be processed, if None all variables are processed.\n    groups : str or list of str, optional\n        Select groups for CDS. Default groups are {\"posterior_groups\", \"prior_groups\",\n        \"posterior_groups_warmup\"}\n            - posterior_groups: posterior, posterior_predictive, sample_stats\n            - prior_groups: prior, prior_predictive, sample_stats_prior\n            - posterior_groups_warmup: warmup_posterior, warmup_posterior_predictive,\n                                       warmup_sample_stats\n    ignore_groups : str or list of str, optional\n        Ignore specific groups from CDS.\n    dimension : str, or list of str, optional\n        Select dimensions along to slice the data. By default uses (\"chain\", \"draw\").\n    group_info : bool\n        Add group info for `var_name_format`\n    var_name_format : str or tuple of tuple of string, optional\n        Select column name format for non-scalar input.\n        Predefined options are {\"brackets\", \"underscore\", \"cds\"}\n            \"brackets\":\n                - add_group_info == False: theta[0,0]\n                - add_group_info == True: theta_posterior[0,0]\n            \"underscore\":\n                - add_group_info == False: theta_0_0\n                - add_group_info == True: theta_posterior_0_0_\n            \"cds\":\n                - add_group_info == False: theta_ARVIZ_CDS_SELECTION_0_0\n                - add_group_info == True: theta_ARVIZ_GROUP_posterior__ARVIZ_CDS_SELECTION_0_0\n            tuple:\n                Structure:\n                    tuple: (dim_info, group_info)\n                        dim_info: (str: `.join` separator,\n                                   str: dim_separator_start,\n                                   str: dim_separator_end)\n                        group_info: (str: group separator start, str: group separator end)\n                Example: ((\",\", \"[\", \"]\"), (\"_\", \"\"))\n                    - add_group_info == False: theta[0,0]\n                    - add_group_info == True: theta_posterior[0,0]\n    index_origin : int, optional\n        Start parameter indices from `index_origin`. Either 0 or 1.\n\n    Returns\n    -------\n    bokeh.models.ColumnDataSource object\n    \"\"\"\n    from ...utils import flatten_inference_data_to_dict\n\n    if var_name_format is None:\n        var_name_format = \"cds\"\n\n    cds_dict = flatten_inference_data_to_dict(\n        data=data,\n        var_names=var_names,\n        groups=groups,\n        dimensions=dimensions,\n        group_info=group_info,\n        index_origin=index_origin,\n        var_name_format=var_name_format,\n    )\n    cds_data = ColumnDataSource(DataFrame.from_dict(cds_dict, orient=\"columns\"))\n    return cds_data\n\n\ndef output_notebook(*args, **kwargs):\n    \"\"\"Wrap bokeh.plotting.output_notebook.\"\"\"\n    import bokeh.plotting as bkp\n\n    return bkp.output_notebook(*args, **kwargs)\n\n\ndef output_file(*args, **kwargs):\n    \"\"\"Wrap bokeh.plotting.output_file.\"\"\"\n    import bokeh.plotting as bkp\n\n    return bkp.output_file(*args, **kwargs)\n\n\ndef ColumnDataSource(*args, **kwargs):\n    \"\"\"Wrap bokeh.models.ColumnDataSource.\"\"\"\n    from bokeh.models import ColumnDataSource\n\n    return ColumnDataSource(*args, **kwargs)\n\n\ndef create_layout(ax, force_layout=False):\n    \"\"\"Transform bokeh array of figures to layout.\"\"\"\n    ax = np.atleast_2d(ax)\n    subplot_order = rcParams[\"plot.bokeh.layout.order\"]\n    if force_layout:\n        from bokeh.layouts import gridplot as layout\n\n        ax = ax.tolist()\n        layout_args = {\n            \"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"],\n            \"toolbar_location\": rcParams[\"plot.bokeh.layout.toolbar_location\"],\n        }\n    elif any(item in subplot_order for item in (\"row\", \"column\")):\n        # check number of rows\n        match = re.match(r\"(\\d*)(row|column)\", subplot_order)\n        n = int(match.group(1)) if match.group(1) is not None else 1\n        subplot_order = match.group(2)\n        # set up 1D list of axes\n        ax = [item for item in ax.ravel().tolist() if item is not None]\n        layout_args = {\"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"]}\n        if subplot_order == \"row\" and n == 1:\n            from bokeh.layouts import row as layout\n        elif subplot_order == \"column\" and n == 1:\n            from bokeh.layouts import column as layout\n        else:\n            from bokeh.layouts import layout\n\n        if n != 1:\n            ax = np.array(ax + [None for _ in range(int(np.ceil(len(ax) / n)) - len(ax))])\n            if subplot_order == \"row\":\n                ax = ax.reshape(n, -1)\n            else:\n                ax = ax.reshape(-1, n)\n            ax = ax.tolist()\n    else:\n        if subplot_order in (\"square\", \"square_trimmed\"):\n            ax = [item for item in ax.ravel().tolist() if item is not None]\n            n = int(np.ceil(len(ax) ** 0.5))\n            ax = ax + [None for _ in range(n ** 2 - len(ax))]\n            ax = np.array(ax).reshape(n, n)\n        ax = ax.tolist()\n        if (subplot_order == \"square_trimmed\") and any(\n            all(item is None for item in row) for row in ax\n        ):\n            from bokeh.layouts import layout\n\n            ax = [row for row in ax if not all(item is None for item in row)]\n            layout_args = {\"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"]}\n        else:\n            from bokeh.layouts import gridplot as layout\n\n            layout_args = {\n                \"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"],\n                \"toolbar_location\": rcParams[\"plot.bokeh.layout.toolbar_location\"],\n            }\n    # ignore \"fixed\" sizing_mode without explicit width and height\n    if layout_args.get(\"sizing_mode\", \"\") == \"fixed\":\n        layout_args.pop(\"sizing_mode\")\n    return layout(ax, **layout_args)\n\n\ndef show_layout(ax, show=True, force_layout=False):\n    \"\"\"Create a layout and call bokeh show.\"\"\"\n    if show is None:\n        show = rcParams[\"plot.bokeh.show\"]\n    if show:\n        import bokeh.plotting as bkp\n\n        layout = create_layout(ax, force_layout=force_layout)\n        bkp.show(layout)\n\n\ndef _copy_docstring(lib, function):\n    \"\"\"Extract docstring from function.\"\"\"\n    import importlib\n\n    try:\n        module = importlib.import_module(lib)\n        func = getattr(module, function)\n        doc = func.__doc__\n    except ImportError:\n        doc = \"Failed to import function {} from {}\".format(function, lib)\n\n    return doc\n\n\noutput_notebook.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.plotting\", \"output_notebook\")\noutput_file.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.plotting\", \"output_file\")\nColumnDataSource.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.models\", \"ColumnDataSource\")\n", "path": "arviz/plots/backends/__init__.py"}], "after_files": [{"content": "# pylint: disable=no-member,invalid-name,redefined-outer-name\n\"\"\"ArviZ plotting backends.\"\"\"\nimport re\nimport numpy as np\nfrom pandas import DataFrame\n\nfrom ...rcparams import rcParams\n\n\ndef to_cds(\n    data,\n    var_names=None,\n    groups=None,\n    dimensions=None,\n    group_info=True,\n    var_name_format=None,\n    index_origin=None,\n):\n    \"\"\"Transform data to ColumnDataSource (CDS) compatible with Bokeh.\n\n    Uses `_ARVIZ_GROUP_` and `_ARVIZ_CDS_SELECTION_`to separate var_name\n    from group and dimensions in CDS columns.\n\n    Parameters\n    ----------\n    data : obj\n        Any object that can be converted to an az.InferenceData object\n        Refer to documentation of az.convert_to_inference_data for details\n    var_names : str or list of str, optional\n        Variables to be processed, if None all variables are processed.\n    groups : str or list of str, optional\n        Select groups for CDS. Default groups are {\"posterior_groups\", \"prior_groups\",\n        \"posterior_groups_warmup\"}\n            - posterior_groups: posterior, posterior_predictive, sample_stats\n            - prior_groups: prior, prior_predictive, sample_stats_prior\n            - posterior_groups_warmup: warmup_posterior, warmup_posterior_predictive,\n                                       warmup_sample_stats\n    ignore_groups : str or list of str, optional\n        Ignore specific groups from CDS.\n    dimension : str, or list of str, optional\n        Select dimensions along to slice the data. By default uses (\"chain\", \"draw\").\n    group_info : bool\n        Add group info for `var_name_format`\n    var_name_format : str or tuple of tuple of string, optional\n        Select column name format for non-scalar input.\n        Predefined options are {\"brackets\", \"underscore\", \"cds\"}\n            \"brackets\":\n                - add_group_info == False: theta[0,0]\n                - add_group_info == True: theta_posterior[0,0]\n            \"underscore\":\n                - add_group_info == False: theta_0_0\n                - add_group_info == True: theta_posterior_0_0_\n            \"cds\":\n                - add_group_info == False: theta_ARVIZ_CDS_SELECTION_0_0\n                - add_group_info == True: theta_ARVIZ_GROUP_posterior__ARVIZ_CDS_SELECTION_0_0\n            tuple:\n                Structure:\n                    tuple: (dim_info, group_info)\n                        dim_info: (str: `.join` separator,\n                                   str: dim_separator_start,\n                                   str: dim_separator_end)\n                        group_info: (str: group separator start, str: group separator end)\n                Example: ((\",\", \"[\", \"]\"), (\"_\", \"\"))\n                    - add_group_info == False: theta[0,0]\n                    - add_group_info == True: theta_posterior[0,0]\n    index_origin : int, optional\n        Start parameter indices from `index_origin`. Either 0 or 1.\n\n    Returns\n    -------\n    bokeh.models.ColumnDataSource object\n    \"\"\"\n    from ...utils import flatten_inference_data_to_dict\n\n    if var_name_format is None:\n        var_name_format = \"cds\"\n\n    cds_dict = flatten_inference_data_to_dict(\n        data=data,\n        var_names=var_names,\n        groups=groups,\n        dimensions=dimensions,\n        group_info=group_info,\n        index_origin=index_origin,\n        var_name_format=var_name_format,\n    )\n    cds_data = ColumnDataSource(DataFrame.from_dict(cds_dict, orient=\"columns\"))\n    return cds_data\n\n\ndef output_notebook(*args, **kwargs):\n    \"\"\"Wrap bokeh.plotting.output_notebook.\"\"\"\n    import bokeh.plotting as bkp\n\n    return bkp.output_notebook(*args, **kwargs)\n\n\ndef output_file(*args, **kwargs):\n    \"\"\"Wrap bokeh.plotting.output_file.\"\"\"\n    import bokeh.plotting as bkp\n\n    return bkp.output_file(*args, **kwargs)\n\n\ndef ColumnDataSource(*args, **kwargs):\n    \"\"\"Wrap bokeh.models.ColumnDataSource.\"\"\"\n    from bokeh.models import ColumnDataSource\n\n    return ColumnDataSource(*args, **kwargs)\n\n\ndef create_layout(ax, force_layout=False):\n    \"\"\"Transform bokeh array of figures to layout.\"\"\"\n    ax = np.atleast_2d(ax)\n    subplot_order = rcParams[\"plot.bokeh.layout.order\"]\n    if force_layout:\n        from bokeh.layouts import gridplot as layout\n\n        ax = ax.tolist()\n        layout_args = {\n            \"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"],\n            \"toolbar_location\": rcParams[\"plot.bokeh.layout.toolbar_location\"],\n        }\n    elif any(item in subplot_order for item in (\"row\", \"column\")):\n        # check number of rows\n        match = re.match(r\"(\\d*)(row|column)\", subplot_order)\n        n = int(match.group(1)) if match.group(1) is not None else 1\n        subplot_order = match.group(2)\n        # set up 1D list of axes\n        ax = [item for item in ax.ravel().tolist() if item is not None]\n        layout_args = {\"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"]}\n        if subplot_order == \"row\" and n == 1:\n            from bokeh.layouts import row as layout\n        elif subplot_order == \"column\" and n == 1:\n            from bokeh.layouts import column as layout\n        else:\n            from bokeh.layouts import layout\n\n        if n != 1:\n            ax = np.array(ax + [None for _ in range(int(np.ceil(len(ax) / n)) - len(ax))])\n            if subplot_order == \"row\":\n                ax = ax.reshape(n, -1)\n            else:\n                ax = ax.reshape(-1, n)\n            ax = ax.tolist()\n    else:\n        if subplot_order in (\"square\", \"square_trimmed\"):\n            ax = [item for item in ax.ravel().tolist() if item is not None]\n            n = int(np.ceil(len(ax) ** 0.5))\n            ax = ax + [None for _ in range(n ** 2 - len(ax))]\n            ax = np.array(ax).reshape(n, n)\n        ax = ax.tolist()\n        if (subplot_order == \"square_trimmed\") and any(\n            all(item is None for item in row) for row in ax\n        ):\n            from bokeh.layouts import layout\n\n            ax = [row for row in ax if not all(item is None for item in row)]\n            layout_args = {\"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"]}\n        else:\n            from bokeh.layouts import gridplot as layout\n\n            layout_args = {\n                \"sizing_mode\": rcParams[\"plot.bokeh.layout.sizing_mode\"],\n                \"toolbar_location\": rcParams[\"plot.bokeh.layout.toolbar_location\"],\n            }\n    # ignore \"fixed\" sizing_mode without explicit width and height\n    if layout_args.get(\"sizing_mode\", \"\") == \"fixed\":\n        layout_args.pop(\"sizing_mode\")\n    return layout(ax, **layout_args)\n\n\ndef show_layout(ax, show=True, force_layout=False):\n    \"\"\"Create a layout and call bokeh show.\"\"\"\n    if show is None:\n        show = rcParams[\"plot.bokeh.show\"]\n    if show:\n        import bokeh.plotting as bkp\n\n        layout = create_layout(ax, force_layout=force_layout)\n        bkp.show(layout)\n\n\ndef _copy_docstring(lib, function):\n    \"\"\"Extract docstring from function.\"\"\"\n    import importlib\n\n    try:\n        module = importlib.import_module(lib)\n        func = getattr(module, function)\n        doc = func.__doc__\n    except ImportError:\n        doc = \"Failed to import function {} from {}\".format(function, lib)\n\n    if not isinstance(doc, str):\n        doc = \"\"\n    return doc\n\n\noutput_notebook.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.plotting\", \"output_notebook\")\noutput_file.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.plotting\", \"output_file\")\nColumnDataSource.__doc__ += \"\\n\\n\" + _copy_docstring(\"bokeh.models\", \"ColumnDataSource\")\n", "path": "arviz/plots/backends/__init__.py"}]}