Sparse coding vs. sparse PCA, are they the same thing? Are they the same thing? If not, could someone possibly explain the difference or point to the seminal papers describing the approaches?  
I am looking not for a detailed technical exposition, but a general taxonomy of the algorithms.  For example, are both of them for dimensionality reduction?
 A: [NB: my original answer was not entirely correct. I revised it now.]
Sparse coding is a problem of representing a collection of $N$ vectors in $d$-dimensional space as linear combinations of some basis vectors, with the requirement that the weights (in linear combinations) should be sparse. Mathematically, if $\mathbf X$ is the data matrix of $N\times d$ size, then you want to find weights $\mathbf W$ and basis vectors $\mathbf T$, such that $$\mathbf X \approx \mathbf W \mathbf T$$ and $\mathbf W$ is a sparse matrix.
I think this term is mostly used in neuroscience, where it is a very popular topic nowadays. It started with the by now classic 1996 Nature paper by Olshausen and Field showing that if applied to a set of natural images, then the basis vectors turn out to resemble receptive fields of the mammalian visual cortex neurons remarkably well. Crucially, for this to work, the basis should be overcomplete, i.e. the number of basis vectors is chosen to be $M \gg N$. There is no desire at all to represent the original dataset with as few basis vectors as possible (like in PCA), it is rather the opposite. For more recent computational ideas on sparse coding, see a popular 2007 paper from the Ng group.


*

*Olshausen and Field, 1996, Emergence of simple-cell receptive field properties by learning a sparse code for natural images

*Lee et al., 2007, Efficient sparse coding algorithms

*Scholarpedia article on sparse coding
In sparse PCA one also wants to represent a collection of vectors as a linear combination of basis vectors (aka principal components). Here the focus, as in traditional PCA, is on choosing a small $m\ll N$ number of basis vectors that together "explain as much variance" as possible, i.e. represent the original data as well as possible. And the sparsity is enforced not on the mapping bases$\to$data, but on the mapping data$\to$bases, because the idea is to have PCs that are linear combinations of only small subsets of original features/vectors (to ease the interpretation).
Mathematically, the formulation here is to find "encoder" $\mathbf A$ and "decoder" $\mathbf B$ such that  $$\mathbf X \approx \mathbf X \mathbf B \mathbf A^\top,$$ subject to sparsity constraints on the decoder $\mathbf B$. Here $\mathbf X \mathbf B$ are sparse PCs (sparse because they are obtained via a sparse decoder) and $\mathbf A$ are loadings.
See the seminal paper by Zou, Hastie, and Tibshirani:


*

*Zou, Hastie, and Tibshirani, 2006, Sparse Principal Component Analysis

As you can see, these two problems are quite different. Sparse coding is not concerned with "decoding" aspect at all, it is only concerned with sparse encoding. Whereas sparse PCA is all about sparse decoding.
A: To complement amoeba's answer, I made the following example to visualize the difference between sklearn's DictionaryLearner (Sparse Coding) and SparsePCA.
>>> import numpy as np
>>> from sklearn.decomposition import DictionaryLearner, SparsePCA
>>> X = np.random.randn(1000, 100)

With DictionaryLearner the code is dense, but the transformed data is sparse:
>>> dict_learner = DictionaryLearning(n_components=50, max_iter=10)
>>> X_code = dict_learner.fit_transform(X)
>>> np.mean(X_code == 0)
0.8
>>> np.mean(dict_learner.components_ == 0)
0.0

With Sparse PCA with code is sparse, but the transformed data is dense:
>>> pca = SparsePCA(n_components=50)
>>> X_pca = pca.fit_transform(X)
>>> np.mean(X_pca == 0)
0.0
>>> np.mean(pca.components_ == 0)
0.759

They both do a reasonable job at reconstructing the original X:
>>> np.linalg.norm(X - X_code @ dict_learner.components_)/np.linalg.norm(X)
0.7383553164896911
>>> np.linalg.norm(X - X_pca @ pca.components_)/np.linalg.norm(X)
0.6361587872554082

Though obviously on random data like this example, you can't expect miracles.
