code: def _eval_bspline_basis(x, knots, degree):
      try:
          from scipy.interpolate import splev
      except ImportError:  # pragma: no cover
          raise ImportError("spline functionality requires scipy")
      # 'knots' are assumed to be already pre-processed. E.g. usually you
      # want to include duplicate copies of boundary knots; you should do
      # that *before* calling this constructor.
      knots = np.atleast_1d(np.asarray(knots, dtype=float))
      assert knots.ndim == 1
      knots.sort()
      degree = int(degree)
      x = np.atleast_1d(x)
      if x.ndim == 2 and x.shape[1] == 1:
          x = x[:, 0]
      assert x.ndim == 1
      # XX FIXME: when points fall outside of the boundaries, splev and R seem
      # to handle them differently. I don't know why yet. So until we understand
      # this and decide what to do with it, I'm going to play it safe and
      # disallow such points.
      if np.min(x) < np.min(knots) or np.max(x) > np.max(knots):
          raise NotImplementedError(
              "some data points fall outside the "
              "outermost knots, and I'm not sure how "
              "to handle them. (Patches accepted!)"
          )
      # Thanks to Charles Harris for explaining splev. It's not well
      # documented, but basically it computes an arbitrary b-spline basis
      # given knots and degree on some specified points (or derivatives
      # thereof, but we don't use that functionality), and then returns some
      # linear combination of these basis functions. To get out the basis
      # functions themselves, we use linear combinations like [1, 0, 0], [0,
      # 1, 0], [0, 0, 1].
      # NB: This probably makes it rather inefficient (though I haven't checked
      # to be sure -- maybe the fortran code actually skips computing the basis
      # function for coefficients that are zero).
      # Note: the order of a spline is the same as its degree + 1.
      # Note: there are (len(knots) - order) basis functions.
      n_bases = len(knots) - (degree + 1)
      basis = np.empty((x.shape[0], n_bases), dtype=float)
      for i in range(n_bases):
          coefs = np.zeros((n_bases,))
          coefs[i] = 1
          basis[:, i] = splev(x, (knots, coefs, degree))
      return basis
  
file_path: patsy/patsy/splines.py
imports: import numpy
  from patsy.util import have_pandas, no_pickling, assert_no_pickling
  from patsy.state import stateful_transform
label_desc: Use image node_id 1 for calling a global function with example usage: _eval_bspline_basis(x, knots, degree) and returns: basis