I'm writing a Python code that's supposed to create a graph and export it as a vector PDF file. I'm using Jupyter Lite at jupyter.org.
I've successfully created the graph, but when I try to export it using plt.savefig() I only get a blank PDF document.
Here's a MWE, because my actual code is rather complex:
import numpy as np;
import matplotlib.pyplot as plt;
geogrph=plt.axes(projection="3d");
thetaE=np.linspace(0,np.pi,501);
phiE=np.linspace(0,2*np.pi,501);
thetaE,phiE=np.meshgrid(thetaE,phiE);
xE=np.sin(thetaE)*np.cos(phiE);
yE=np.sin(thetaE)*np.sin(phiE);
zE=np.cos(thetaE);
geogrph.plot_surface(xE,yE,zE);
plt.savefig("geogrph.pdf");
(I know it isn't necessary to add a semicolon at the end of each line of code in Python. It's a habit from coding in Mathematica and in C++, and it does avoid Jupyter outputting random nonsense like <matplotlib.legend.Legend at 0x29e4950> if I use a legend or other such things. Since it does no harm and does have a small benefit, I choose to do it.)
As stated, the above code outputs a blank PDF file. It does display the expected graph on the Jupyter front end (see below), but it can't save it for some reason. I'm aware that plt.show() causes this behaviour and should therefore be placed after plt.savefig(), but I'm not even using plt.show() in this case, so I don't know what's going on.
I read somewhere this can happen when %matplotlib inline is enabled and it can be solved by switching to %matplotlib notebook. However, running that command produces an error:
(...) ImportError: cannot import name 'alert' from 'js' (unknown location)"],"output_type":"error"}],"execution_count":236}]
I then read somewhere else that ipympl needs to be installed for the switch to work, so I tried adding pip install ipympl at the beginning of the cell. However, I'm still getting the aforementioned error.
I'm super-new to Python, in case it wasn't obvious. My experience is mostly with Mathematica and MatLab, and I'm not used to this sort of error, so I have no idea how to debug this.
Thanks in advance for any help.
Combining my comments and those of @furas into a step-by-step with example code (this was before any code was provided):
JupyterLite is very new and experimental, see here and the introduction section at the top the JupyterLite intro.ipynb notebook. You'll likely want to adapt all your code to work with it. (If you don't wish to do that, one option is to continue to use a typical, standard ipykernel. You can still easily do that without installing anything on your own machine by going to the repos Jupyter interfaces here & here, and then clicking on the offered 'launch binder' badges to get a temporary session on a remote computer served via the MyBinder.org service. This has been what all of Try Jupyter used. Recently the popular choices were changed to JupyterLite to take demand of the servers that cost money since it was clearly under the 'Try' umbrella and JupyterLite gets the points of the interface basics across.)
The JupyterLite intro.ipynb notebook includes a single code cell and this is actually a plotting example. However, it just makes a matplotlib object displaying the plot and you want to save an image file. So this step-by-step will cover doing that with current JupyterLite offered from the Try Jupyter Page at jupyter.org.
Getting Started
Go to the Try Jupyter Page at jupyter.org and click on 'JupyterLab' tile in the upper left. (You could also select the Jupyter Notebook tile; however, that adds additional steps that I'll talk about later.) If you have the ability, do this in a new 'incognito' or 'private browsing' browser window.
When the session comes up...If you were able to open in a new 'incognito' or 'private browsing' browser window You'll see the JupyterLite intro.ipynb notebook and the only code cell on that page is the the plotting example. If you weren't able to start out fresh in a new 'incognito' or 'private browsing' browser window, you'll likely see the JupyterLite in the state you last interacted with it. Hopefully, there is an intro.ipynb file listed in the left panel and you can double click to open that. (Don't worry if you happened to delete the file or change it. You can use the nbviewer link to the static view of the code here, copy that code to a new notebook in JupyterLite and continue on with the 'adapting' section below.)
You'll note the plotting example in the JupyterLite intro.ipynb notebook for JupyterLite, doesn't have %matplotlib inline. Or any %matplotlib line. The default in modern Jupyter is %matplotlib inline and so it is no longer needed. You don't want ``%matplotlib notebook` in modern Jupyter. That is legacy code from a time when JupyterLab and Jupyter Notebook didn't essentially use the same components behind the scenes.
Adapting the code to save an image of the plot
Copy the code from the code cell.
Then open a new notebook file in JupyterLite and paste in the code from the intro.ipynb as if you were going to run it. Except you are going to make a change so you can make an image file.
change the final line from plt.show() to plt.savefig('test_plot.png'). Meaning you'd have the following code in your code cell:
from matplotlib import pyplot as plt
import numpy as np
# Generate 100 random data points along 3 dimensions
x, y, scale = np.random.randn(3, 100)
fig, ax = plt.subplots()
# Map each onto a scatterplot we'll create with Matplotlib
ax.scatter(x=x, y=y, c=scale, s=np.abs(scale)*500)
ax.set(title="Some random data, created with JupyterLab!")
plt.savefig('test_plot.png')
Run the adapted code and you'll see in the file navigation panel on the left now, a file test_plot.png show up. You successfully made the image file instead of only displaying the associated matplotlib object in the running .ipynb file. As @furas pointed out, if you had simply put plt.savefig('test_plot.png') after the plt.show(), you'd end of with blank images like you were seeing. This is because the plt.show() essentially clears the active matplotlib object at the conclusion of displaying it, and so there is no active matplotlib object to be saved as an image. And actually plt.show() is largely no longer needed as modern Jupyter will display any active current matplotlib object present when the last code in the cell is run.
That produced image file is deep in your browser's virtual file system so you can pretty much treat it as if you Jupyter session were running on a remote server. If that were the case, you'd download the file to your local machine to view the image file locally. I'm going to suggest doing that. So right click on the image file in the file browser panel on the left and choose 'Download'. Then save the file to your normal computer's operating system file system.
Open the image file as you would any image you downloaded from the internet. Keep the file on your computer's file system if you don't want to lose it when your browser gets updated or refreshed. I'd argue any time you create a useful .ipynb file in JupyterLite, you should also right-click on that file download and store that in your local filesystem as if the JupyterLite session would disappear at any moment. At this time, here is no real persistence for the files in JupyterLite since it is in a virtual file system running deep in your browser and if something changes with your browser or you move to another browse/computer, you lose access. (You'd probably want to rename the particular intro.ipynb file involved here in the process so you know what it is in the future.)
(Running new sessions incognito or in 'private browsing' mode allows you to get a fresh session and more easily see what you encounter if you change browsers or computers or otherwise update your browser's local storage somehow.)
Why did I suggest JupyterLab for the demo? Can I use Jupyter Notebook in JupyterLite and still save an image file of my plot?
JupyterLab makes seeing you can still use JupyterLite to make image files of plots easier. It also makes obtaining the produced image file and associated notebook code and storing them on your local filesystem easier. (Remember don't use JupyterLite for persistence, at this time.)
You can though do that step-by-step process with Jupyter Notebook as well.
Here is the outline of how:
For step #1 above, choose a different tile. On the Try Jupyter page at Jupyter.org, select the 'Jupyter Notebook' tile that is to the right of the JupyterLab tile at this time, and click on that for the launch. Try to do it incognito or in private broswer session as I suggest above in order to get
You'll get a JupyterLite session with the Jupyter Notebook interface. Go ahead and run the adapted code supplied above to make the image file, test_plot.png. Because you aren't in JupyterLab, you won't easily see an indicate the file was made. However, you can display the generated image in your running Jupyter Notebook session by pasting in the following code in the next cell and executing it:
from IPython.display import Image
Image("test_plot.png")
Upon executing that code, you should see in the new cell's output area the image you generated with plt.savefig('test_plot.png').
To download the image file and the notebook that produced it, click on the JupyterLite logo in the upper left of your browser. Alternatively, use the menu to select 'View' > 'File browser'. Either will give you the Jupyter Dashboard view. You can right click on the image file and download it. You can do the same with the notebook file to save the code that produced it. This is essentially the last part of the main step-by-step section above.
ipympl
In the example, I shared you don't need ipympl. You didn't share your code so it is hard to say if you needed it or not. I suspect you didn't. As it makes clear here, ipympl is for running interactive plots in modern Jupyter. You seemed to want to make an image file of the generated plot and so ipympl would not be appropriate at all. ipympl is for making matplotlib objects that can be interacted with and not for saving image files.
My experience is that at present ipympl doesn't work in the experimental JupyterLite. So lets assume you are using a standard kernel to continue to discuss ipympl...
ipympl doesn't need to be installed for the backend you wanted. (Maybe you misunderstood something that lead to you writing, "I then read somewhere else that ipympl needs to be installed for the switch to work".) It would need to be installed for %matplotlib ipympl to work. The ipympl documentation includes such an example here. (There you'll see that also allows the older %matplotlib widget syntax to work; however, I would caution being more explicit is better for you and everyone following your code. As a result, I suggest explicitly using %matplotlib ipympl in any such cases. Addressing "I tried adding pip install ipympl at the beginning of the cell": also it is always best to run installations in separate cells because for best results you should be re-starting the kernel before running any code dependent on what you just installed. So you could run %pip install ipympl in a cell before. [The use of % is important, see here.] Then let it complete and restart the kernel. ipympl actually changes a lot of things and so often a refresh of the browser page is necessary or it will act like ipympl isn't working. Indeed, it is even best to install ipympl first and then start a session as it can still be temperamental using install commands in cells for very complex packages. Again, this is at present for a standard ipykernel and not for JupyterLite. See my text above of "option is to continue to use a typical, standard ipykernel" for a way to get such a temporary session without installing anything. These can be made to be quite complex via configuration files with packages already available at launch time, as shown with the example 'Geospatial analytics in Python with Geopandas' highlighted here.)