Jupyter: Replot in different cell - python

I'd like to do something like this:
import matplotlib.pyplot as plt
%matplotlib inline
fig1 = plt.figure(1)
plt.plot([1,2,3],[5,2,4])
plt.show()
In one cell, and then redraw the exact same plot in another cell, like so:
plt.figure(1) # attempting to reference the figure I created earlier...
# four things I've tried:
plt.show() # does nothing... :(
fig1.show() # throws warning about backend and does nothing
fig1.draw() # throws error about renderer
fig1.plot([1,2,3],[5,2,4]) # This also doesn't work (jupyter outputs some
# text saying matplotlib.figure.Figure at 0x..., changing the backend and
# using plot don't help with that either), but regardless in reality
# these plots have a lot going on and I'd like to recreate them
# without running all of the same commands over again.
I've messed around with some combinations of this stuff as well but nothing works.
This question is similar to IPython: How to show the same plot in different cells? but I'm not particularly looking to update my plot, I just want to redraw it.

I have found a solution to do this. The trick is to create a figure with an axis fig, ax = plt.subplots() and use the axis to plot. Then we can just call fig at the end of any other cell we want to replot the figure.
import matplotlib.pyplot as plt
import numpy as np
x_1 = np.linspace(-.5,3.3,50)
y_1 = x_1**2 - 2*x_1 + 1
fig, ax = plt.subplots()
plt.title('Reusing this figure', fontsize=20)
ax.plot(x_1, y_1)
ax.set_xlabel('x',fontsize=18)
ax.set_ylabel('y',fontsize=18, rotation=0, labelpad=10)
ax.legend(['Eq 1'])
ax.axis('equal');
This produces
Now we can add more things by using the ax object:
t = np.linspace(0,2*np.pi,100)
h, a = 2, 2
k, b = 2, 3
x_2 = h + a*np.cos(t)
y_2 = k + b*np.sin(t)
ax.plot(x_2,y_2)
ax.legend(['Eq 1', 'Eq 2'])
fig
Note how I just wrote fig in the last line, making the notebook output the figure once again.
I hope this helps!

Related

how to show multiple graphs at once? (class)

Hi everyone:) I would like to ask for some help to make a class that I can use to plot graphs. i have an excel sheet with different countries and their corresponding air pollution levels. i need to plot graphs for each country. this is the code used to plot my graphs:
import matplotlib.pyplot as plt
import numpy as np
x = df_full_filtered.loc[(df_full_filtered['AirPollutant'] == 'PM10') & (df_full_filtered['Country']
== 'Italy')]['AirPollutionLevel']
plt.style.use('ggplot')
plt.hist(x, bins=80)
plt.show()
y = df_full_filtered.loc[(df_full_filtered['AirPollutant'] == 'PM10') & (df_full_filtered['Country']
== 'Germany')]['AirPollutionLevel']
plt.style.use('ggplot')
plt.hist(y, bins=80)
plt.show()
everytime i run my code, it stops running everytime it reaches the plt.show code and wont continue running till you manually close the popup window with the first graph. is there any way i can surpass this?
edit: i tried putting both codes for x and y under each other and inserting plt.plot(x,y) but they have different shapes (rows/columns in the excel file)
thanks
You need to create two figures.
Method 1
data = [i**2 for i in range(100)]
plt.figure(1)
plt.hist(data, bins = 5)
plt.figure(2)
plt.hist(data, bins = 10)
plt.show()
Method 2
data = [i**2 for i in range(100)]
fig1, ax1 = plt.subplots()
ax1.hist(data, bins = 5)
fig2, ax2 = plt.subplots()
ax2.hist(data, bins = 10)
plt.show()
(If you need, you can call them the same name, i.e. the second figure and axes could be named fig1 and ax1, as well.)
Method 1 is the direct answer to your code. Method 2 is another way of using Matplotlib. (see https://matplotlib.org/matplotblog/posts/pyplot-vs-object-oriented-interface/)

Adjust the shape of figures with/without colorbar

I have a code to plot a figure.
When I run this code without adding plt.colorbar(), I can get a figure which looks more like a rectangle. However, if I add colorbar, the shape change to look like a square.
How can I add colorbar and maintain the original shape of the figure? Thanks!!!
#%%
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
x = np.random.rand(10000)
y = np.random.rand(10000)
plt.scatter(x,y,c=y)
#plt.colorbar()
plt.show()
Following this documentation, you need to add some settings to axes. Your script works for me in a right ways if I insert these rows after creation of fig:
ax = plt.gca()
ax.set_aspect('equal', 'box')

about .show() of matplotlib

I am working with matplotlib to generate some graphs but I do not know the difference between these two ways of showing an image. I already read some documentation about it but I do not understand yet.
First way:
import matplotlib.pyplot as plt
plt.figure()
plt.plot(x, y)
plt.show()
Second way:
import matplotlib.pyplot as plt
graph = plt.figure()
plt.plot(x, y)
graph.show()
I think this two ways do not do the same thing but it is not clear to me.
Could someone explain it step by step for the two ways?
Simplified, plt.show() will start an event loop and create a graphical representation for each figure that is active inside the pyplot state.
In contrast, fig.show(), where fig is a figure instance, would show only this figure. Since it would also not block, it is (only) useful in interactive sessions; else the figure would be closed directly after showing it due to the script exiting.
In the usual case you would hence prefer plt.show(). This does not prevent you from using the object-oriented interface. A recommended way of creating and showing a figure is hence,
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
For two windows you can just repeat the plotting,
import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots()
ax1.plot(x1, y1)
fig2, ax2 = plt.subplots()
ax2.plot(x2, y2)
plt.show()
Matplotlib has two styles of API implemented. One is object based (graph.show()) and the other is procedural (plt.show()) and looks a lot like the Matlab plotting API.
The procedural API works on the current figure and/or set of axes. You can always getting the current figure with plt.gcf() and the current axes with plt.gca().
There are occasionally some slight differences in syntax here and there. For example, if you want to set the x axis limits:
plt.xlim([0, 10])
or
ax = plt.gca()
ax.set_xlim([0, 10])
plt.figure returns an object that is assigned with graph = plt.figure() to graph . this is used when specific characteristics of this object ( the plot ) are intended to be changed, now the object can be refered to by its instance graph ( object-based plotting )
you use this i.e. if you want to access the axes of the graph or labels, subplots, ...
see https://python4mpia.github.io/plotting/advanced.html for object-based plotting
to manipulate the plot object you have to get a reference to it ( handle ) and this is done by graph = plt.figure() ( cf Object-Oriented Programming )

Accessing axis or figure in python ggplot

python ggplot is great, but still new, and I find the need to fallback on traditional matplotlib techniques to modify my plots. But I'm not sure how to either pass an axis instance to ggplot, or get one back from it.
So let's say I build a plot like so:
import ggplot as gp
(explicit import)
p = gp.ggplot(gp.aes(x='basesalary', y='compensation'), data = df)
p + gp.geom_histogram(binwidth = 10000)
No problems so far. But now let's say I want the y-axis in log scale. I'd like to be able to do this:
plt.gca().set_yscale('log')
Unfortunately, plt.gca() doesn't access the axis created by ggplot. I end up with two figures: the histogram from ggplot in linear scale, and an empty figure with a log-scale y axis.
I've tried a few variations with both gca() and gcf() without success.
There might have been some changes since 2013 when this question was asked. The way to produce a matplotlib figure from a ggplot is
g.make()
after that, figure and axes can be obtained via
fig = plt.gcf()
ax = plt.gca()
or, if there are more axes, axes = fig.axes.
Then, additional features can be added in matplotlib, like also shown in this question's answer.
Finally the plot can be saved using the usual savefig command.
Complete example:
import ggplot as gp
import matplotlib.pyplot as plt
# produce ggplot
g = gp.ggplot(gp.aes(x='carat', y='price'), data=gp.diamonds)
g = g + gp.geom_point()
g = g + gp.ylab(' ')+ gp.xlab(' ')
# Make
g.make()
# obtain figure from ggplot
fig = plt.gcf()
ax = plt.gca()
# adjust some of the ggplot axes' parameters
ax.set_title("ggplot plot")
ax.set_xlabel("Some x label")
plt.savefig(__file__+".png")
plt.show()
[This is outdated with current ggpy]
There is now a scale_y_log(). If you want to do something in matplotlib, you can get the current figure/axis with
g = ggplot(...)
fig = g.draw()
#or
g.draw() # or print(g)
fig = plt.gcf()
ax = plt.gca()
Your version fails because ggplots draws the plot on print(g) in the ggplot.__repr__() method (which calls ggplot.draw()), so there is simple no matplotlib figure right after constructing the ggplot object but only after print (or g.draw()). g.draw() also returns the figure, so you don't need to use plt.gcf()
Did you try:
p = gp.ggplot(gp.aes(x='basesalary', y='compensation'), data = df)
p + gp.geom_histogram(binwidth = 10000) + gp.scale_y_log()
Not sure if it works just like that though, just guessing from looking at the code...

Python (Matplotlib) - show multiple figures (plots) with an x and/or y offset (so without overlapping)

I'm trying to show multiple figures at once, but with an offset so I don't have to move the first figure to check that it showed all the figures (plots).
So here's an example:
from pylab import *
figure(0)
plot()
figure(1)
plot()
show()
These figures are shown on top of each other, but I want them to look like this when I run my program:
EDIT:
Any suggestions?
I usually do this with Figure.add_subplot:
fig = figure(0)
ax = fig.add_subplot(211)
ax.plot(...)
ax = fig.add_subplot(212)
ax.plot(...)
show()
If you're wondering what the magic 211 and 212 mean, see this question.
If you're using the tkagg backend, you can do:
import matplotlib.pyplot as plt
for i in range(5):
fig = plt.figure()
fig.canvas._tkcanvas.master.geometry('800x600+{:d}+{:d}'.format(70*i,70*i))
plt.show()
I think that the same treatment could be used for others backends...
Regards

Categories