From a physics perspective, why does D/A quantization error result in a noise floor?
For the last week or so I have been trying to understand how quantization error results in the noise floor outside of a mathematical perspective and I haven't really had any luck finding a source that discussed quantization noise without using equations to show where quantization error comes from.


That's because it's a purely mathematical effect, there's no physics involved.

It's technically quantization distortion, not noise, but we simplify the analysis by treating it as a noise source.

But it's really not; it's nonlinear distortion, so the spectrum of the quantization error varies with the signal.  Maybe that's where you're confused?  

For instance, if you sample a sine wave that's a sub-multiple of the sampling rate and quantize it:



you will get harmonic distortion only at specific frequencies:



If it's not an exact sub-multiple, the infinite number of harmonics produced by the distortion will alias and produce a more noise-like residual:



Since this sort of behavior is more common with arbitrary signals, it's usually treated like a noise source.  In addition, we usually randomize this distortion by adding a small amount of dither noise to the analog signal before quantization, which flattens out the spectrum, reducing the peak value of the distortion and making the noise unrelated to the signal, so we are actually forcing it to be a true noise source rather than a distortion:



from __future__ import division
from numpy import linspace, round, abs, sin, log10, pi
from numpy.fft import rfft
from numpy.random import randn
from scipy.signal import hamming as window
import matplotlib.pyplot as plt

fs = 5000  # Hz
t = linspace(0, 1, fs, endpoint=False)
f = 25  # Hz
x = sin(2*pi*f*t)
plt.figure(1)
plt.plot(x)
plt.figure(2)

x += randn(fs)/20  # Dither
x = round(x*5)/5  # Quantization

plt.plot(20*log10(1/fs * abs(rfft(window(fs)*x))))
plt.ylim(-100, 0)
plt.figure(1)
plt.plot(x)
plt.margins(0, 0.1)