def generate_X_grid(self, term, n=100, meshgrid=False):
        if not self._is_fitted:
            raise AttributeError('GAM has not been fitted. Call fit first.')
        if self.terms[term].isintercept:
            raise ValueError('cannot create grid for intercept term')
        if self.terms[term].istensor:
            Xs = []
            for term_ in self.terms[term]:
                Xs.append(np.linspace(term_.edge_knots_[0],
                                      term_.edge_knots_[1],
                                      num=n))
            Xs = np.meshgrid(*Xs, indexing='ij')
            if meshgrid:
                return tuple(Xs)
            else:
                return self._flatten_mesh(Xs, term=term)
        elif hasattr(self.terms[term], 'edge_knots_'):
            x = np.linspace(self.terms[term].edge_knots_[0],
                            self.terms[term].edge_knots_[1],
                            num=n)
            if meshgrid:
                return (x,)
            X = np.zeros((n, self.statistics_['m_features']))
            X[:, self.terms[term].feature] = x
            if getattr(self.terms[term], 'by', None) is not None:
                X[:, self.terms[term].by] = 1.
            return X
        else:
            raise TypeError('Unexpected term type: {}'.format(self.terms[term]))