Just how good is MP3, anyway? I wondered this during my recent struggle with decoding MP3 files. File formats are chosen based on tradeoffs, and with digital media the tradeoffs tend to coalesce around two variables: quality and size. Inspired by a few recent experiments at RC to visualize data loss in digital media, I wanted to answer this question for myself. My idea is to compare the spectrograms of different audio formats to get a sense of which frequencies are being left out by codec compression techniques. From there, it might be possible to visualize (or hear) the data left behind. It’s an interesting task, and I’m eager to tackle it.
But this post isn’t about spectrograms or compression or anything fancy. This is about installing matplotlib.
I want to write a program to compute the spectrogram of a piece of audio. To do so, it’d be helpful to see the spectrogram, if for no reason other than to sanity-check a major component of the project (the whole “generating a spectrogram” part). I googled “python spectrogram”, clicked the first link, fired up my Python interpreter, and tapped away at the keyboard. You can probably guess where I got stuck.
~/d/python-scratch $ python -c 'import matplotlib.pyplot as plt' Traceback (most recent call last): File "<string>", line 1, in <module> File "/Users/rorysawyer/.pyenv/versions/3.6.3/lib/python3.6/site-packages/matplotlib/pyplot.py", line 115, in <module> _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() File "/Users/rorysawyer/.pyenv/versions/3.6.3/lib/python3.6/site-packages/matplotlib/backends/__init__.py", line 62, in pylab_setup [backend_name], 0) File "/Users/rorysawyer/.pyenv/versions/3.6.3/lib/python3.6/site-packages/matplotlib/backends/backend_macosx.py", line 17, in <module> from matplotlib.backends import _macosx RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using (Ana)Conda please install python.app and replace the use of 'python' with 'pythonw'. See 'Working with Matplotlib on OSX' in the Matplotlib FAQ for more information.
Python’s dependency management is officially a joke, but still, this is a bit of a doozy. From what I can tell, matplotlib.pyplot was… not imported.
At the time of this error, I was using pyenv and pyenv-virtualenv to manage Python stuff for me. I haven’t had to maintain a Python codebase since 2015, and at that time I was using one version of Python and virtualenv and that worked out just fine. I threw pyenv and pyenv-virtualenv on my computer earlier this year and they’ve also been working out just fine (until now). Pyenv is just managing my Python versions for me, but there is precedent for extra setup steps needed to run matplotlib so I fired up pyenv-virtualenv to try and have a clean slate to work from.
I then realized that I had never set up pyenv-virtualenv correctly. Earlier this year I installed fish shell. It seemingly has all the things I liked about zsh, but now every shell script I come across needs a few character changes to run properly. Following the instructions to get fish shell to cooperate didn’t work on the first try, so I thought I’d try out Python’s endorsement for dependency management: pipenv.
Based on the few minutes I spent installing pipenv, verifying that it installed properly, and then fumbling around with it, I feel confident that pipenv will work out just fine. I still ran into the error of matplotlib needing a “framework version of Python” (whatever that is), so pipenv was at least as good as pyenv and pyenv-virtualenv. What really changed my opinion about pipenv was googling
pipenv matplotlib. While searching
pyenv matplotlib yielded links to github issues with comments like “all I had to do was add this one line to my .bash_profile”, the pipenv search yielded this github issue, which linked to this comment on another github issue, which said to “add this one line to your ~/.matplotlib/matplotlibrc file”. I created that file, added that line, and:
(python-scratch-mAt2ZSfq) (python-scratch-mAt2ZSfq) ~/d/python-scratch $ python -c 'import matplotlib.pyplot as plt' (python-scratch-mAt2ZSfq) (python-scratch-mAt2ZSfq) ~/d/python-scratch $
Now that I had fixed my problem, it was time to figure out what was wrong. Matplotlib relies on a backend, which I think is a specific set of capabilities based on the use case in which matplotlib finds itself. Matplotlib is sometimes embedded into GUIs and sometimes called from the command line. In a way to make the library a little more portable, the public API (which they call the “frontend”) is separate from the code that needs to render images (this is the “backend”). Thinking this through, it makes a lot of sense, although I’m not sure why I only had this issue with the pyplot module.
In short, matplotlib.pyplot needs a backend and I wasn’t telling it which one to use.
However, when I started this journey, I wasn’t thinking of this as an issue with matplotlib. I thought this was an issue with Python’s dependency management, or my local Python setup, or some third thing I didn’t know about but assumed resided within the hornets nest of Python setups and dependency management.
Is there something to be learned here? I learned a little bit more about how matplotlib is structured. I learned that pipenv is ok. I might have a cleaner Python setup out of all of this. Mostly, though, I think the lessons are 1) don’t underestimate the task at hand and 2) don’t let initial feelings/perceptions/reactions guide the whole bug search. I incorrectly assumed that this issue was about dependency management. Dependency management is one of my least favorite programming issues. As a result, I showed this issue no respect and received none in return. At least I got a working matplotlib installation out of it.