We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CmdStanPy tests
Add tests for CmdStanPy. See if we can read cmdstan output csv to PosterierSample which then can be tested.

--- 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/data/io_cmdstanpy.py`
Content:
```
1 """CmdStan-specific conversion code."""
2 from collections import defaultdict
3 from copy import deepcopy
4 import logging
5 import re
6 
7 
8 import numpy as np
9 import xarray as xr
10 
11 from .inference_data import InferenceData
12 from .base import requires, dict_to_dataset, generate_dims_coords, make_attrs
13 
14 
15 _log = logging.getLogger(__name__)
16 
17 
18 class CmdStanPyConverter:
19     """Encapsulate CmdStanPy specific logic."""
20 
21     # pylint: disable=too-many-instance-attributes
22 
23     def __init__(
24         self,
25         *,
26         posterior=None,
27         posterior_predictive=None,
28         prior=None,
29         prior_predictive=None,
30         observed_data=None,
31         log_likelihood=None,
32         coords=None,
33         dims=None
34     ):
35         self.posterior = posterior
36         self.posterior_predictive = posterior_predictive
37         self.prior = prior
38         self.prior_predictive = prior_predictive
39         self.observed_data = observed_data
40         self.log_likelihood = log_likelihood
41         self.coords = coords
42         self.dims = dims
43 
44         import cmdstanpy  # pylint: disable=import-error
45 
46         self.cmdstanpy = cmdstanpy
47 
48     @requires("posterior")
49     def posterior_to_xarray(self):
50         """Extract posterior samples from output csv."""
51         columns = self.posterior.column_names
52 
53         # filter posterior_predictive and log_likelihood
54         posterior_predictive = self.posterior_predictive
55         if posterior_predictive is None:
56             posterior_predictive = []
57         elif isinstance(posterior_predictive, str):
58             posterior_predictive = [
59                 col for col in columns if posterior_predictive == col.split(".")[0]
60             ]
61         else:
62             posterior_predictive = [
63                 col
64                 for col in columns
65                 if any(item == col.split(".")[0] for item in posterior_predictive)
66             ]
67 
68         log_likelihood = self.log_likelihood
69         if log_likelihood is None:
70             log_likelihood = []
71         else:
72             log_likelihood = [col for col in columns if log_likelihood == col.split(".")[0]]
73 
74         invalid_cols = (
75             posterior_predictive + log_likelihood + [col for col in columns if col.endswith("__")]
76         )
77         valid_cols = [col for col in columns if col not in invalid_cols]
78         data = _unpack_frame(self.posterior.sample, columns, valid_cols)
79         return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)
80 
81     @requires("posterior")
82     def sample_stats_to_xarray(self):
83         """Extract sample_stats from fit."""
84         dtypes = {"divergent__": bool, "n_leapfrog__": np.int64, "treedepth__": np.int64}
85 
86         columns = self.posterior.column_names
87         valid_cols = [col for col in columns if col.endswith("__")]
88         # copy dims and coords
89         dims = deepcopy(self.dims) if self.dims is not None else {}
90         coords = deepcopy(self.coords) if self.coords is not None else {}
91 
92         log_likelihood = self.log_likelihood
93         if isinstance(log_likelihood, str):
94             valid_cols.append(log_likelihood)
95 
96             log_likelihood_cols = [col for col in columns if log_likelihood == col.split(".")[0]]
97             # change dims and coords for log_likelihood if defined
98             if log_likelihood in dims:
99                 dims["log_likelihood"] = dims.pop(log_likelihood)
100 
101             log_likelihood_dims = np.array(
102                 [list(map(int, col.split(".")[1:])) for col in log_likelihood_cols]
103             )
104             max_dims = log_likelihood_dims.max(0)
105             max_dims = max_dims if hasattr(max_dims, "__iter__") else (max_dims,)
106             default_dim_names, _ = generate_dims_coords(shape=max_dims, var_name=log_likelihood)
107             log_likelihood_dim_names, _ = generate_dims_coords(
108                 shape=max_dims, var_name="log_likelihood"
109             )
110             for default_dim_name, log_likelihood_dim_name in zip(
111                 default_dim_names, log_likelihood_dim_names
112             ):
113                 if default_dim_name in coords:
114                     coords[log_likelihood_dim_name] = coords.pop(default_dim_name)
115 
116         data = _unpack_frame(self.posterior.sample, columns, valid_cols)
117         for s_param in list(data.keys()):
118             s_param_, *_ = s_param.split(".")
119             name = re.sub("__$", "", s_param_)
120             name = "diverging" if name == "divergent" else name
121             data[name] = data.pop(s_param).astype(dtypes.get(s_param, float))
122         return dict_to_dataset(data, library=self.cmdstanpy, coords=coords, dims=dims)
123 
124     @requires("posterior")
125     @requires("posterior_predictive")
126     def posterior_predictive_to_xarray(self):
127         """Convert posterior_predictive samples to xarray."""
128         posterior_predictive = self.posterior_predictive
129         columns = self.posterior.column_names
130 
131         if isinstance(posterior_predictive, str):
132             posterior_predictive = [posterior_predictive]
133         valid_cols = [col for col in columns if col.split(".")[0] in set(posterior_predictive)]
134         data = _unpack_frame(self.posterior.sample, columns, valid_cols)
135         return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)
136 
137     @requires("prior")
138     def prior_to_xarray(self):
139         """Convert prior samples to xarray."""
140         # filter prior_predictive
141         columns = self.prior.column_names
142 
143         # filter posterior_predictive and log_likelihood
144         prior_predictive = self.prior_predictive
145         if prior_predictive is None:
146             prior_predictive = []
147         elif isinstance(prior_predictive, str):
148             prior_predictive = [col for col in columns if prior_predictive == col.split(".")[0]]
149         else:
150             prior_predictive = [
151                 col for col in columns if col.split(".")[0] in set(prior_predictive)
152             ]
153 
154         valid_cols = [col for col in columns if col not in set(prior_predictive)]
155         data = _unpack_frame(self.posterior.sample, columns, valid_cols)
156         return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)
157 
158     @requires("prior")
159     def sample_stats_prior_to_xarray(self):
160         """Extract sample_stats from fit."""
161         dtypes = {"divergent__": bool, "n_leapfrog__": np.int64, "treedepth__": np.int64}
162 
163         columns = self.prior.column_names
164         valid_cols = [col for col in columns if col.endswith("__")]
165         # copy dims and coords
166         dims = deepcopy(self.dims) if self.dims is not None else {}
167         coords = deepcopy(self.coords) if self.coords is not None else {}
168 
169         data = _unpack_frame(self.prior.sample, columns, valid_cols)
170         for s_param in list(data.keys()):
171             s_param_, *_ = s_param.split(".")
172             name = re.sub("__$", "", s_param_)
173             name = "diverging" if name == "divergent" else name
174             data[name] = data.pop(s_param).astype(dtypes.get(s_param, float))
175         return dict_to_dataset(data, library=self.cmdstanpy, coords=coords, dims=dims)
176 
177     @requires("prior")
178     @requires("prior_predictive")
179     def prior_predictive_to_xarray(self):
180         """Convert prior_predictive samples to xarray."""
181         prior_predictive = self.prior_predictive
182         columns = self.prior.column_names
183 
184         if isinstance(prior_predictive, str):
185             prior_predictive = [prior_predictive]
186         valid_cols = [col for col in columns if col.split(".")[0] in set(prior_predictive)]
187         data = _unpack_frame(self.prior.sample, columns, valid_cols)
188         return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)
189 
190     @requires("observed_data")
191     def observed_data_to_xarray(self):
192         """Convert observed data to xarray."""
193         observed_data = {}
194         for key, vals in self.observed_data.items():
195             vals = np.atleast_1d(vals)
196             val_dims = self.dims.get(key)
197             val_dims, coords = generate_dims_coords(
198                 vals.shape, key, dims=val_dims, coords=self.coords
199             )
200             observed_data[key] = xr.DataArray(vals, dims=val_dims, coords=coords)
201         return xr.Dataset(data_vars=observed_data, attrs=make_attrs(library=self.cmdstanpy))
202 
203     def to_inference_data(self):
204         """Convert all available data to an InferenceData object.
205 
206         Note that if groups can not be created (i.e., there is no `output`, so
207         the `posterior` and `sample_stats` can not be extracted), then the InferenceData
208         will not have those groups.
209         """
210         return InferenceData(
211             **{
212                 "posterior": self.posterior_to_xarray(),
213                 "sample_stats": self.sample_stats_to_xarray(),
214                 "posterior_predictive": self.posterior_predictive_to_xarray(),
215                 "prior": self.prior_to_xarray(),
216                 "sample_stats_prior": self.sample_stats_prior_to_xarray(),
217                 "prior_predictive": self.prior_predictive_to_xarray(),
218                 "observed_data": self.observed_data_to_xarray(),
219             }
220         )
221 
222 
223 def _unpack_frame(data, columns, valid_cols):
224     """Transform a list of pandas.DataFrames to dictionary containing ndarrays.
225 
226     Parameters
227     ----------
228     data : np.ndarray
229     columns : list
230     valid_cols : list
231 
232     Returns
233     -------
234     dict
235         key, values pairs. Values are formatted to shape = (chains, draws, *shape)
236     """
237     draws, chains, *_ = data.shape
238 
239     column_groups = defaultdict(list)
240     column_locs = defaultdict(list)
241     # iterate flat column names
242     for i, col in enumerate(columns):
243         # parse parameter names e.g. X.1.2 --> X, (1,2)
244         col_base, *col_tail = col.split(".")
245         if len(col_tail):
246             # gather nD array locations
247             column_groups[col_base].append(tuple(map(int, col_tail)))
248         # gather raw data locations for each parameter
249         column_locs[col_base].append(i)
250     dims = {}
251     for colname, col_dims in column_groups.items():
252         # gather parameter dimensions (assumes dense arrays)
253         dims[colname] = tuple(np.array(col_dims).max(0))
254     sample = {}
255     valid_base_cols = []
256     # get list of parameters for extraction (basename) X.1.2 --> X
257     for col in valid_cols:
258         base_col, *_ = col.split(".")
259         if base_col not in valid_base_cols:
260             valid_base_cols.append(base_col)
261 
262     # extract each wanted parameter to ndarray with correct shape
263     for key in valid_base_cols:
264         ndim = dims.get(key, None)
265         shape_location = column_groups.get(key, None)
266         if ndim is not None:
267             sample[key] = np.full((chains, draws, *ndim), np.nan)
268         if shape_location is None:
269             # reorder draw, chain -> chain, draw
270             i, = column_locs[key]
271             sample[key] = np.swapaxes(data[..., i], 0, 1)
272         else:
273             for i, shape_loc in zip(column_locs[key], shape_location):
274                 # location to insert extracted array
275                 shape_loc = tuple([Ellipsis] + [j - 1 for j in shape_loc])
276                 # reorder draw, chain -> chain, draw and insert to ndarray
277                 sample[key][shape_loc] = np.swapaxes(data[..., i], 0, 1)
278     return sample
279 
280 
281 def from_cmdstanpy(
282     posterior=None,
283     *,
284     posterior_predictive=None,
285     prior=None,
286     prior_predictive=None,
287     observed_data=None,
288     log_likelihood=None,
289     coords=None,
290     dims=None
291 ):
292     """Convert CmdStan data into an InferenceData object.
293 
294     Parameters
295     ----------
296     posterior : PosteriorSample object
297         PyCmdStan PosteriorSample
298     posterior_predictive : str, list of str
299         Posterior predictive samples for the fit.
300     prior : PosteriorSample
301         PyCmdStan PosteriorSample
302     prior_predictive : str, list of str
303         Prior predictive samples for the fit.
304     observed_data : dict
305         Observed data used in the sampling.
306     log_likelihood : str
307         Pointwise log_likelihood for the data.
308     coords : dict of str or dict of iterable
309         A dictionary containing the values that are used as index. The key
310         is the name of the dimension, the values are the index values.
311     dims : dict of str or list of str
312         A mapping from variables to a list of coordinate names for the variable.
313 
314     Returns
315     -------
316     InferenceData object
317     """
318     return CmdStanPyConverter(
319         posterior=posterior,
320         posterior_predictive=posterior_predictive,
321         prior=prior,
322         prior_predictive=prior_predictive,
323         observed_data=observed_data,
324         log_likelihood=log_likelihood,
325         coords=coords,
326         dims=dims,
327     ).to_inference_data()
328
```
--- 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/data/io_cmdstanpy.py b/arviz/data/io_cmdstanpy.py
--- a/arviz/data/io_cmdstanpy.py
+++ b/arviz/data/io_cmdstanpy.py
@@ -114,6 +114,8 @@
                     coords[log_likelihood_dim_name] = coords.pop(default_dim_name)
 
         data = _unpack_frame(self.posterior.sample, columns, valid_cols)
+        if log_likelihood in data:
+            data["log_likelihood"] = data.pop(log_likelihood)
         for s_param in list(data.keys()):
             s_param_, *_ = s_param.split(".")
             name = re.sub("__$", "", s_param_)
@@ -193,7 +195,7 @@
         observed_data = {}
         for key, vals in self.observed_data.items():
             vals = np.atleast_1d(vals)
-            val_dims = self.dims.get(key)
+            val_dims = self.dims.get(key) if self.dims is not None else None
             val_dims, coords = generate_dims_coords(
                 vals.shape, key, dims=val_dims, coords=self.coords
             )

{"golden_diff": "diff --git a/arviz/data/io_cmdstanpy.py b/arviz/data/io_cmdstanpy.py\n--- a/arviz/data/io_cmdstanpy.py\n+++ b/arviz/data/io_cmdstanpy.py\n@@ -114,6 +114,8 @@\n                     coords[log_likelihood_dim_name] = coords.pop(default_dim_name)\n \n         data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n+        if log_likelihood in data:\n+            data[\"log_likelihood\"] = data.pop(log_likelihood)\n         for s_param in list(data.keys()):\n             s_param_, *_ = s_param.split(\".\")\n             name = re.sub(\"__$\", \"\", s_param_)\n@@ -193,7 +195,7 @@\n         observed_data = {}\n         for key, vals in self.observed_data.items():\n             vals = np.atleast_1d(vals)\n-            val_dims = self.dims.get(key)\n+            val_dims = self.dims.get(key) if self.dims is not None else None\n             val_dims, coords = generate_dims_coords(\n                 vals.shape, key, dims=val_dims, coords=self.coords\n             )\n", "issue": "CmdStanPy tests\nAdd tests for CmdStanPy. See if we can read cmdstan output csv to PosterierSample which then can be tested.\n", "before_files": [{"content": "\"\"\"CmdStan-specific conversion code.\"\"\"\nfrom collections import defaultdict\nfrom copy import deepcopy\nimport logging\nimport re\n\n\nimport numpy as np\nimport xarray as xr\n\nfrom .inference_data import InferenceData\nfrom .base import requires, dict_to_dataset, generate_dims_coords, make_attrs\n\n\n_log = logging.getLogger(__name__)\n\n\nclass CmdStanPyConverter:\n    \"\"\"Encapsulate CmdStanPy specific logic.\"\"\"\n\n    # pylint: disable=too-many-instance-attributes\n\n    def __init__(\n        self,\n        *,\n        posterior=None,\n        posterior_predictive=None,\n        prior=None,\n        prior_predictive=None,\n        observed_data=None,\n        log_likelihood=None,\n        coords=None,\n        dims=None\n    ):\n        self.posterior = posterior\n        self.posterior_predictive = posterior_predictive\n        self.prior = prior\n        self.prior_predictive = prior_predictive\n        self.observed_data = observed_data\n        self.log_likelihood = log_likelihood\n        self.coords = coords\n        self.dims = dims\n\n        import cmdstanpy  # pylint: disable=import-error\n\n        self.cmdstanpy = cmdstanpy\n\n    @requires(\"posterior\")\n    def posterior_to_xarray(self):\n        \"\"\"Extract posterior samples from output csv.\"\"\"\n        columns = self.posterior.column_names\n\n        # filter posterior_predictive and log_likelihood\n        posterior_predictive = self.posterior_predictive\n        if posterior_predictive is None:\n            posterior_predictive = []\n        elif isinstance(posterior_predictive, str):\n            posterior_predictive = [\n                col for col in columns if posterior_predictive == col.split(\".\")[0]\n            ]\n        else:\n            posterior_predictive = [\n                col\n                for col in columns\n                if any(item == col.split(\".\")[0] for item in posterior_predictive)\n            ]\n\n        log_likelihood = self.log_likelihood\n        if log_likelihood is None:\n            log_likelihood = []\n        else:\n            log_likelihood = [col for col in columns if log_likelihood == col.split(\".\")[0]]\n\n        invalid_cols = (\n            posterior_predictive + log_likelihood + [col for col in columns if col.endswith(\"__\")]\n        )\n        valid_cols = [col for col in columns if col not in invalid_cols]\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"posterior\")\n    def sample_stats_to_xarray(self):\n        \"\"\"Extract sample_stats from fit.\"\"\"\n        dtypes = {\"divergent__\": bool, \"n_leapfrog__\": np.int64, \"treedepth__\": np.int64}\n\n        columns = self.posterior.column_names\n        valid_cols = [col for col in columns if col.endswith(\"__\")]\n        # copy dims and coords\n        dims = deepcopy(self.dims) if self.dims is not None else {}\n        coords = deepcopy(self.coords) if self.coords is not None else {}\n\n        log_likelihood = self.log_likelihood\n        if isinstance(log_likelihood, str):\n            valid_cols.append(log_likelihood)\n\n            log_likelihood_cols = [col for col in columns if log_likelihood == col.split(\".\")[0]]\n            # change dims and coords for log_likelihood if defined\n            if log_likelihood in dims:\n                dims[\"log_likelihood\"] = dims.pop(log_likelihood)\n\n            log_likelihood_dims = np.array(\n                [list(map(int, col.split(\".\")[1:])) for col in log_likelihood_cols]\n            )\n            max_dims = log_likelihood_dims.max(0)\n            max_dims = max_dims if hasattr(max_dims, \"__iter__\") else (max_dims,)\n            default_dim_names, _ = generate_dims_coords(shape=max_dims, var_name=log_likelihood)\n            log_likelihood_dim_names, _ = generate_dims_coords(\n                shape=max_dims, var_name=\"log_likelihood\"\n            )\n            for default_dim_name, log_likelihood_dim_name in zip(\n                default_dim_names, log_likelihood_dim_names\n            ):\n                if default_dim_name in coords:\n                    coords[log_likelihood_dim_name] = coords.pop(default_dim_name)\n\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        for s_param in list(data.keys()):\n            s_param_, *_ = s_param.split(\".\")\n            name = re.sub(\"__$\", \"\", s_param_)\n            name = \"diverging\" if name == \"divergent\" else name\n            data[name] = data.pop(s_param).astype(dtypes.get(s_param, float))\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=coords, dims=dims)\n\n    @requires(\"posterior\")\n    @requires(\"posterior_predictive\")\n    def posterior_predictive_to_xarray(self):\n        \"\"\"Convert posterior_predictive samples to xarray.\"\"\"\n        posterior_predictive = self.posterior_predictive\n        columns = self.posterior.column_names\n\n        if isinstance(posterior_predictive, str):\n            posterior_predictive = [posterior_predictive]\n        valid_cols = [col for col in columns if col.split(\".\")[0] in set(posterior_predictive)]\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"prior\")\n    def prior_to_xarray(self):\n        \"\"\"Convert prior samples to xarray.\"\"\"\n        # filter prior_predictive\n        columns = self.prior.column_names\n\n        # filter posterior_predictive and log_likelihood\n        prior_predictive = self.prior_predictive\n        if prior_predictive is None:\n            prior_predictive = []\n        elif isinstance(prior_predictive, str):\n            prior_predictive = [col for col in columns if prior_predictive == col.split(\".\")[0]]\n        else:\n            prior_predictive = [\n                col for col in columns if col.split(\".\")[0] in set(prior_predictive)\n            ]\n\n        valid_cols = [col for col in columns if col not in set(prior_predictive)]\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"prior\")\n    def sample_stats_prior_to_xarray(self):\n        \"\"\"Extract sample_stats from fit.\"\"\"\n        dtypes = {\"divergent__\": bool, \"n_leapfrog__\": np.int64, \"treedepth__\": np.int64}\n\n        columns = self.prior.column_names\n        valid_cols = [col for col in columns if col.endswith(\"__\")]\n        # copy dims and coords\n        dims = deepcopy(self.dims) if self.dims is not None else {}\n        coords = deepcopy(self.coords) if self.coords is not None else {}\n\n        data = _unpack_frame(self.prior.sample, columns, valid_cols)\n        for s_param in list(data.keys()):\n            s_param_, *_ = s_param.split(\".\")\n            name = re.sub(\"__$\", \"\", s_param_)\n            name = \"diverging\" if name == \"divergent\" else name\n            data[name] = data.pop(s_param).astype(dtypes.get(s_param, float))\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=coords, dims=dims)\n\n    @requires(\"prior\")\n    @requires(\"prior_predictive\")\n    def prior_predictive_to_xarray(self):\n        \"\"\"Convert prior_predictive samples to xarray.\"\"\"\n        prior_predictive = self.prior_predictive\n        columns = self.prior.column_names\n\n        if isinstance(prior_predictive, str):\n            prior_predictive = [prior_predictive]\n        valid_cols = [col for col in columns if col.split(\".\")[0] in set(prior_predictive)]\n        data = _unpack_frame(self.prior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"observed_data\")\n    def observed_data_to_xarray(self):\n        \"\"\"Convert observed data to xarray.\"\"\"\n        observed_data = {}\n        for key, vals in self.observed_data.items():\n            vals = np.atleast_1d(vals)\n            val_dims = self.dims.get(key)\n            val_dims, coords = generate_dims_coords(\n                vals.shape, key, dims=val_dims, coords=self.coords\n            )\n            observed_data[key] = xr.DataArray(vals, dims=val_dims, coords=coords)\n        return xr.Dataset(data_vars=observed_data, attrs=make_attrs(library=self.cmdstanpy))\n\n    def to_inference_data(self):\n        \"\"\"Convert all available data to an InferenceData object.\n\n        Note that if groups can not be created (i.e., there is no `output`, so\n        the `posterior` and `sample_stats` can not be extracted), then the InferenceData\n        will not have those groups.\n        \"\"\"\n        return InferenceData(\n            **{\n                \"posterior\": self.posterior_to_xarray(),\n                \"sample_stats\": self.sample_stats_to_xarray(),\n                \"posterior_predictive\": self.posterior_predictive_to_xarray(),\n                \"prior\": self.prior_to_xarray(),\n                \"sample_stats_prior\": self.sample_stats_prior_to_xarray(),\n                \"prior_predictive\": self.prior_predictive_to_xarray(),\n                \"observed_data\": self.observed_data_to_xarray(),\n            }\n        )\n\n\ndef _unpack_frame(data, columns, valid_cols):\n    \"\"\"Transform a list of pandas.DataFrames to dictionary containing ndarrays.\n\n    Parameters\n    ----------\n    data : np.ndarray\n    columns : list\n    valid_cols : list\n\n    Returns\n    -------\n    dict\n        key, values pairs. Values are formatted to shape = (chains, draws, *shape)\n    \"\"\"\n    draws, chains, *_ = data.shape\n\n    column_groups = defaultdict(list)\n    column_locs = defaultdict(list)\n    # iterate flat column names\n    for i, col in enumerate(columns):\n        # parse parameter names e.g. X.1.2 --> X, (1,2)\n        col_base, *col_tail = col.split(\".\")\n        if len(col_tail):\n            # gather nD array locations\n            column_groups[col_base].append(tuple(map(int, col_tail)))\n        # gather raw data locations for each parameter\n        column_locs[col_base].append(i)\n    dims = {}\n    for colname, col_dims in column_groups.items():\n        # gather parameter dimensions (assumes dense arrays)\n        dims[colname] = tuple(np.array(col_dims).max(0))\n    sample = {}\n    valid_base_cols = []\n    # get list of parameters for extraction (basename) X.1.2 --> X\n    for col in valid_cols:\n        base_col, *_ = col.split(\".\")\n        if base_col not in valid_base_cols:\n            valid_base_cols.append(base_col)\n\n    # extract each wanted parameter to ndarray with correct shape\n    for key in valid_base_cols:\n        ndim = dims.get(key, None)\n        shape_location = column_groups.get(key, None)\n        if ndim is not None:\n            sample[key] = np.full((chains, draws, *ndim), np.nan)\n        if shape_location is None:\n            # reorder draw, chain -> chain, draw\n            i, = column_locs[key]\n            sample[key] = np.swapaxes(data[..., i], 0, 1)\n        else:\n            for i, shape_loc in zip(column_locs[key], shape_location):\n                # location to insert extracted array\n                shape_loc = tuple([Ellipsis] + [j - 1 for j in shape_loc])\n                # reorder draw, chain -> chain, draw and insert to ndarray\n                sample[key][shape_loc] = np.swapaxes(data[..., i], 0, 1)\n    return sample\n\n\ndef from_cmdstanpy(\n    posterior=None,\n    *,\n    posterior_predictive=None,\n    prior=None,\n    prior_predictive=None,\n    observed_data=None,\n    log_likelihood=None,\n    coords=None,\n    dims=None\n):\n    \"\"\"Convert CmdStan data into an InferenceData object.\n\n    Parameters\n    ----------\n    posterior : PosteriorSample object\n        PyCmdStan PosteriorSample\n    posterior_predictive : str, list of str\n        Posterior predictive samples for the fit.\n    prior : PosteriorSample\n        PyCmdStan PosteriorSample\n    prior_predictive : str, list of str\n        Prior predictive samples for the fit.\n    observed_data : dict\n        Observed data used in the sampling.\n    log_likelihood : str\n        Pointwise log_likelihood for the data.\n    coords : dict of str or dict of iterable\n        A dictionary containing the values that are used as index. The key\n        is the name of the dimension, the values are the index values.\n    dims : dict of str or list of str\n        A mapping from variables to a list of coordinate names for the variable.\n\n    Returns\n    -------\n    InferenceData object\n    \"\"\"\n    return CmdStanPyConverter(\n        posterior=posterior,\n        posterior_predictive=posterior_predictive,\n        prior=prior,\n        prior_predictive=prior_predictive,\n        observed_data=observed_data,\n        log_likelihood=log_likelihood,\n        coords=coords,\n        dims=dims,\n    ).to_inference_data()\n", "path": "arviz/data/io_cmdstanpy.py"}], "after_files": [{"content": "\"\"\"CmdStan-specific conversion code.\"\"\"\nfrom collections import defaultdict\nfrom copy import deepcopy\nimport logging\nimport re\n\n\nimport numpy as np\nimport xarray as xr\n\nfrom .inference_data import InferenceData\nfrom .base import requires, dict_to_dataset, generate_dims_coords, make_attrs\n\n\n_log = logging.getLogger(__name__)\n\n\nclass CmdStanPyConverter:\n    \"\"\"Encapsulate CmdStanPy specific logic.\"\"\"\n\n    # pylint: disable=too-many-instance-attributes\n\n    def __init__(\n        self,\n        *,\n        posterior=None,\n        posterior_predictive=None,\n        prior=None,\n        prior_predictive=None,\n        observed_data=None,\n        log_likelihood=None,\n        coords=None,\n        dims=None\n    ):\n        self.posterior = posterior\n        self.posterior_predictive = posterior_predictive\n        self.prior = prior\n        self.prior_predictive = prior_predictive\n        self.observed_data = observed_data\n        self.log_likelihood = log_likelihood\n        self.coords = coords\n        self.dims = dims\n\n        import cmdstanpy  # pylint: disable=import-error\n\n        self.cmdstanpy = cmdstanpy\n\n    @requires(\"posterior\")\n    def posterior_to_xarray(self):\n        \"\"\"Extract posterior samples from output csv.\"\"\"\n        columns = self.posterior.column_names\n\n        # filter posterior_predictive and log_likelihood\n        posterior_predictive = self.posterior_predictive\n        if posterior_predictive is None:\n            posterior_predictive = []\n        elif isinstance(posterior_predictive, str):\n            posterior_predictive = [\n                col for col in columns if posterior_predictive == col.split(\".\")[0]\n            ]\n        else:\n            posterior_predictive = [\n                col\n                for col in columns\n                if any(item == col.split(\".\")[0] for item in posterior_predictive)\n            ]\n\n        log_likelihood = self.log_likelihood\n        if log_likelihood is None:\n            log_likelihood = []\n        else:\n            log_likelihood = [col for col in columns if log_likelihood == col.split(\".\")[0]]\n\n        invalid_cols = (\n            posterior_predictive + log_likelihood + [col for col in columns if col.endswith(\"__\")]\n        )\n        valid_cols = [col for col in columns if col not in invalid_cols]\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"posterior\")\n    def sample_stats_to_xarray(self):\n        \"\"\"Extract sample_stats from fit.\"\"\"\n        dtypes = {\"divergent__\": bool, \"n_leapfrog__\": np.int64, \"treedepth__\": np.int64}\n\n        columns = self.posterior.column_names\n        valid_cols = [col for col in columns if col.endswith(\"__\")]\n        # copy dims and coords\n        dims = deepcopy(self.dims) if self.dims is not None else {}\n        coords = deepcopy(self.coords) if self.coords is not None else {}\n\n        log_likelihood = self.log_likelihood\n        if isinstance(log_likelihood, str):\n            valid_cols.append(log_likelihood)\n\n            log_likelihood_cols = [col for col in columns if log_likelihood == col.split(\".\")[0]]\n            # change dims and coords for log_likelihood if defined\n            if log_likelihood in dims:\n                dims[\"log_likelihood\"] = dims.pop(log_likelihood)\n\n            log_likelihood_dims = np.array(\n                [list(map(int, col.split(\".\")[1:])) for col in log_likelihood_cols]\n            )\n            max_dims = log_likelihood_dims.max(0)\n            max_dims = max_dims if hasattr(max_dims, \"__iter__\") else (max_dims,)\n            default_dim_names, _ = generate_dims_coords(shape=max_dims, var_name=log_likelihood)\n            log_likelihood_dim_names, _ = generate_dims_coords(\n                shape=max_dims, var_name=\"log_likelihood\"\n            )\n            for default_dim_name, log_likelihood_dim_name in zip(\n                default_dim_names, log_likelihood_dim_names\n            ):\n                if default_dim_name in coords:\n                    coords[log_likelihood_dim_name] = coords.pop(default_dim_name)\n\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        if log_likelihood in data:\n            data[\"log_likelihood\"] = data.pop(log_likelihood)\n        for s_param in list(data.keys()):\n            s_param_, *_ = s_param.split(\".\")\n            name = re.sub(\"__$\", \"\", s_param_)\n            name = \"diverging\" if name == \"divergent\" else name\n            data[name] = data.pop(s_param).astype(dtypes.get(s_param, float))\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=coords, dims=dims)\n\n    @requires(\"posterior\")\n    @requires(\"posterior_predictive\")\n    def posterior_predictive_to_xarray(self):\n        \"\"\"Convert posterior_predictive samples to xarray.\"\"\"\n        posterior_predictive = self.posterior_predictive\n        columns = self.posterior.column_names\n\n        if isinstance(posterior_predictive, str):\n            posterior_predictive = [posterior_predictive]\n        valid_cols = [col for col in columns if col.split(\".\")[0] in set(posterior_predictive)]\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"prior\")\n    def prior_to_xarray(self):\n        \"\"\"Convert prior samples to xarray.\"\"\"\n        # filter prior_predictive\n        columns = self.prior.column_names\n\n        # filter posterior_predictive and log_likelihood\n        prior_predictive = self.prior_predictive\n        if prior_predictive is None:\n            prior_predictive = []\n        elif isinstance(prior_predictive, str):\n            prior_predictive = [col for col in columns if prior_predictive == col.split(\".\")[0]]\n        else:\n            prior_predictive = [\n                col for col in columns if col.split(\".\")[0] in set(prior_predictive)\n            ]\n\n        valid_cols = [col for col in columns if col not in set(prior_predictive)]\n        data = _unpack_frame(self.posterior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"prior\")\n    def sample_stats_prior_to_xarray(self):\n        \"\"\"Extract sample_stats from fit.\"\"\"\n        dtypes = {\"divergent__\": bool, \"n_leapfrog__\": np.int64, \"treedepth__\": np.int64}\n\n        columns = self.prior.column_names\n        valid_cols = [col for col in columns if col.endswith(\"__\")]\n        # copy dims and coords\n        dims = deepcopy(self.dims) if self.dims is not None else {}\n        coords = deepcopy(self.coords) if self.coords is not None else {}\n\n        data = _unpack_frame(self.prior.sample, columns, valid_cols)\n        for s_param in list(data.keys()):\n            s_param_, *_ = s_param.split(\".\")\n            name = re.sub(\"__$\", \"\", s_param_)\n            name = \"diverging\" if name == \"divergent\" else name\n            data[name] = data.pop(s_param).astype(dtypes.get(s_param, float))\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=coords, dims=dims)\n\n    @requires(\"prior\")\n    @requires(\"prior_predictive\")\n    def prior_predictive_to_xarray(self):\n        \"\"\"Convert prior_predictive samples to xarray.\"\"\"\n        prior_predictive = self.prior_predictive\n        columns = self.prior.column_names\n\n        if isinstance(prior_predictive, str):\n            prior_predictive = [prior_predictive]\n        valid_cols = [col for col in columns if col.split(\".\")[0] in set(prior_predictive)]\n        data = _unpack_frame(self.prior.sample, columns, valid_cols)\n        return dict_to_dataset(data, library=self.cmdstanpy, coords=self.coords, dims=self.dims)\n\n    @requires(\"observed_data\")\n    def observed_data_to_xarray(self):\n        \"\"\"Convert observed data to xarray.\"\"\"\n        observed_data = {}\n        for key, vals in self.observed_data.items():\n            vals = np.atleast_1d(vals)\n            val_dims = self.dims.get(key) if self.dims is not None else None\n            val_dims, coords = generate_dims_coords(\n                vals.shape, key, dims=val_dims, coords=self.coords\n            )\n            observed_data[key] = xr.DataArray(vals, dims=val_dims, coords=coords)\n        return xr.Dataset(data_vars=observed_data, attrs=make_attrs(library=self.cmdstanpy))\n\n    def to_inference_data(self):\n        \"\"\"Convert all available data to an InferenceData object.\n\n        Note that if groups can not be created (i.e., there is no `output`, so\n        the `posterior` and `sample_stats` can not be extracted), then the InferenceData\n        will not have those groups.\n        \"\"\"\n        return InferenceData(\n            **{\n                \"posterior\": self.posterior_to_xarray(),\n                \"sample_stats\": self.sample_stats_to_xarray(),\n                \"posterior_predictive\": self.posterior_predictive_to_xarray(),\n                \"prior\": self.prior_to_xarray(),\n                \"sample_stats_prior\": self.sample_stats_prior_to_xarray(),\n                \"prior_predictive\": self.prior_predictive_to_xarray(),\n                \"observed_data\": self.observed_data_to_xarray(),\n            }\n        )\n\n\ndef _unpack_frame(data, columns, valid_cols):\n    \"\"\"Transform a list of pandas.DataFrames to dictionary containing ndarrays.\n\n    Parameters\n    ----------\n    data : np.ndarray\n    columns : list\n    valid_cols : list\n\n    Returns\n    -------\n    dict\n        key, values pairs. Values are formatted to shape = (chains, draws, *shape)\n    \"\"\"\n    draws, chains, *_ = data.shape\n\n    column_groups = defaultdict(list)\n    column_locs = defaultdict(list)\n    # iterate flat column names\n    for i, col in enumerate(columns):\n        # parse parameter names e.g. X.1.2 --> X, (1,2)\n        col_base, *col_tail = col.split(\".\")\n        if len(col_tail):\n            # gather nD array locations\n            column_groups[col_base].append(tuple(map(int, col_tail)))\n        # gather raw data locations for each parameter\n        column_locs[col_base].append(i)\n    dims = {}\n    for colname, col_dims in column_groups.items():\n        # gather parameter dimensions (assumes dense arrays)\n        dims[colname] = tuple(np.array(col_dims).max(0))\n    sample = {}\n    valid_base_cols = []\n    # get list of parameters for extraction (basename) X.1.2 --> X\n    for col in valid_cols:\n        base_col, *_ = col.split(\".\")\n        if base_col not in valid_base_cols:\n            valid_base_cols.append(base_col)\n\n    # extract each wanted parameter to ndarray with correct shape\n    for key in valid_base_cols:\n        ndim = dims.get(key, None)\n        shape_location = column_groups.get(key, None)\n        if ndim is not None:\n            sample[key] = np.full((chains, draws, *ndim), np.nan)\n        if shape_location is None:\n            # reorder draw, chain -> chain, draw\n            i, = column_locs[key]\n            sample[key] = np.swapaxes(data[..., i], 0, 1)\n        else:\n            for i, shape_loc in zip(column_locs[key], shape_location):\n                # location to insert extracted array\n                shape_loc = tuple([Ellipsis] + [j - 1 for j in shape_loc])\n                # reorder draw, chain -> chain, draw and insert to ndarray\n                sample[key][shape_loc] = np.swapaxes(data[..., i], 0, 1)\n    return sample\n\n\ndef from_cmdstanpy(\n    posterior=None,\n    *,\n    posterior_predictive=None,\n    prior=None,\n    prior_predictive=None,\n    observed_data=None,\n    log_likelihood=None,\n    coords=None,\n    dims=None\n):\n    \"\"\"Convert CmdStan data into an InferenceData object.\n\n    Parameters\n    ----------\n    posterior : PosteriorSample object\n        PyCmdStan PosteriorSample\n    posterior_predictive : str, list of str\n        Posterior predictive samples for the fit.\n    prior : PosteriorSample\n        PyCmdStan PosteriorSample\n    prior_predictive : str, list of str\n        Prior predictive samples for the fit.\n    observed_data : dict\n        Observed data used in the sampling.\n    log_likelihood : str\n        Pointwise log_likelihood for the data.\n    coords : dict of str or dict of iterable\n        A dictionary containing the values that are used as index. The key\n        is the name of the dimension, the values are the index values.\n    dims : dict of str or list of str\n        A mapping from variables to a list of coordinate names for the variable.\n\n    Returns\n    -------\n    InferenceData object\n    \"\"\"\n    return CmdStanPyConverter(\n        posterior=posterior,\n        posterior_predictive=posterior_predictive,\n        prior=prior,\n        prior_predictive=prior_predictive,\n        observed_data=observed_data,\n        log_likelihood=log_likelihood,\n        coords=coords,\n        dims=dims,\n    ).to_inference_data()\n", "path": "arviz/data/io_cmdstanpy.py"}]}