Returns the MCMC samples in a nice, neat pandas DataFrame with all MCMC chains
        concatenated.

        Args:
            varnames (list): List of variable names to include; if None
                (default), all eligible variables are included.
            ranefs (bool): Whether or not to include random effects in the
                returned DataFrame. Default is True.
            transformed (bool): Whether or not to include internally
                transformed variables in the result. Default is False.
            chains (int, list): Index, or list of indexes, of chains to
                concatenate. E.g., [1, 3] would concatenate the first and
                third chains, and ignore any others. If None (default),
                concatenates all available chains.

def to_df(self, varnames=None, ranefs=False, transformed=False,
              chains=None):
        '''
        Returns the MCMC samples in a nice, neat pandas DataFrame with all MCMC chains
        concatenated.

        Args:
            varnames (list): List of variable names to include; if None
                (default), all eligible variables are included.
            ranefs (bool): Whether or not to include random effects in the
                returned DataFrame. Default is True.
            transformed (bool): Whether or not to include internally
                transformed variables in the result. Default is False.
            chains (int, list): Index, or list of indexes, of chains to
                concatenate. E.g., [1, 3] would concatenate the first and
                third chains, and ignore any others. If None (default),
                concatenates all available chains.
        '''

        # filter out unwanted variables
        names = self._filter_names(varnames, ranefs, transformed)

        # concatenate the (pre-sliced) chains
        if chains is None:
            chains = list(range(self.n_chains))
        chains = listify(chains)
        data = [self.data[:, i, :] for i in chains]
        data = np.concatenate(data, axis=0)

        # construct the trace DataFrame
        df = sum([self.level_dict[x] for x in names], [])
        df = pd.DataFrame({x: data[:, self.levels.index(x)] for x in df})

        return df