Saving plots as variables in python like in R - python

When I work in R's ggplot() I can store my plots as p<-ggplot()... This makes it easier to add elements to the plot and look at them before they are saved. Is there a way to do this in python? For example, I would like to be able to add elements to the first figure, fig, after I plot the new z values.
What ggplot can do with R.
library(ggplot2)
p<-ggplot(mtcars,aes(x=factor(am),y=mpg))+geom_boxplot()
p+xlab("Transmission Type")+ylab("Miles Per Gallon (mpg)")
p
What I would like to do in Python.
import matplotlib.pyplot as plt
x = [1,2,3]
y = [2,4,1]
fig = plt.plot(x, y)
z = x*2
y = [2,4,1]
fig2 = plt.plot(z, y)
fig.show()
fig2.show()

Related

How to assign a plot to a variable and use the variable in a multiplot in Python

I would like to have a function which create a plot. Once I have the plot, I would like to use that in a multiplot.
For example, I could create the following function:
def fig_1(x):
# create a new figure
fig = plt.figure()
plt.plot([1*x, 2*x, 3*x, 4*x])
return fig
after that I would like something like:
subplot(3,2,1) = fig_1(1)
subplot(3,2,2) = fig_1(2)
subplot(3,2,3) = fig_1(3)
subplot(3,2,4) = fig_1(4)
subplot(3,2,5) = fig_1(5)
subplot(3,2,6) = fig_1(6)
In order to plot the final plot:
from pylab import *
pdf = matplotlib.backends.backend_pdf.PdfPages("Cal8010.pdf")
for fig in xrange(1,figure().number):
In this way, it does not work. Could I do what I have in mind?
Thanks for any kind of help
First: I create subplots and in each one a plot:
import matplotlib.pyplot as plt
import numpy as np
def fig_1(ax, x, y):
ax.plot(x, y)
fig, ax = plt.subplots(3, 2)
for i in range(3):
for j in range(2):
x = np.random.random(10)
y = np.random.random(10)
fig_1(ax[i, j], x, y)
ax[i, j].set_title(f"Subplot #{2*i + j + 1}")
plt.show()
Now, you can also plot an empty array and further update datas to this plot:
import matplotlib.pyplot as plt
import numpy as np
def fig_1(ax):
line, = ax.plot([], [])
return line
fig, ax = plt.subplots(3, 2)
lines = []
for i in range(3):
for j in range(2):
x = np.random.random(10)
y = np.random.random(10)
lines.append((fig_1(ax[i, j]), x, y))
ax[i, j].set_title(f"Subplot #{2*i + j + 1}")
for p in lines:
l, x, y = p
l.set_xdata(x)
l.set_ydata(y)
fig.canvas.draw()
fig.canvas.flush_events()
plt.show()
but this could be tricky because both axis on each plot are not adapted to the datas so plots can be out of bounds (so you possibly need to fix the x and y limits to min and max of datas)
Dear Reviewer,
here the solution that I have work out thanks to another post that I hope to find again in order to give the right credit to it.
fig, axs = plt.subplots(2,2)
def plot_ff(ax=None,data):
ax.plot(data)
return
plot_ff(axs[0, 0],data_1)
plot_ff(axs[0, 1],data_2)
plot_ff(axs[1, 0],data_3)
plot_ff(axs[0, 1],data_3)
In this way, it works and it is easily manage with different type of multiplot
What do you think about this solution?
Should I erase this questions?
Diego

Is there a way to plot a polar heatmap incrementally?

I am trying to have a polar heatmap appear incrementally. I want the plot to grow by adding a deltasector to the existing plot. The same maximal radius is always used.
For now I replot the old data as well, but that is only because I do not know how to add to the existing plot.
How do I add z values for the new angle to an existing heatmap?
The accepted answer here gives shows how to plot a polar heatmap:
Polar heatmaps in python
In the code below the z values are calculated as a function of the r and th. My situation is however that I read the values from a file instead.
How would I add them to the heatmap?
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import time
fig = plt.figure()
ax = Axes3D(fig)
angle = 0
rad = np.linspace(0, 5, 100)
d_angle = np.pi/100
while angle < np.pi:
azm = np.linspace(0, angle, 100)
r, th = np.meshgrid(rad, azm)
z = r/5
plt.subplot(projection="polar")
plt.pcolormesh(th, r, z)
plt.plot(azm, r, color='k', ls='none')
plt.grid()
plt.ion()
plt.show()
plt.pause(0.0001)
plt.clf()
angle += d_angle
I do not know where to start. Any pointers to docs? Or other advices?
You can retrieve the data from a plot by looking into ax.lines. Add a "gid" to your curve like so plt.plot(azm, r, color='k', ls='none', gid="a custom name") then we have a little work to do:
def append_data_to_curve(ax, gid):
for line in ax.lines: # Check every curve.
if line.get_gid() == "a custom name": # If the one you seek is found:
X = line.get_xdata() # Get its X and Y data.
Y = line.get_ydata()
X.append(x) # Add the new point (x,y) you want.
Y.append(y)
line.set_xdata(X) # Put back the modified list as curve data.
line.set_ydata(Y)
You can call this function for every iteration of a loop and add a single new point by giving it its (x,y) coordinates.

Retrieve matplotlib ContourSet for SymPy plots

Using SymPy, I can create a contour plot manually using the following code (there isn't yet a built-in contour plotting function Update: SymPy now has a contour plotting function):
from sympy import init_session
init_session()
from sympy.plotting.plot import Plot, ContourSeries
# show plot centered at 0,0
x_min = -7
x_max = 7
y_min = -5
y_max = 5
# contour plot of inverted cone
my_plot = Plot(
ContourSeries(
sqrt(x**2 + y**2),
(x,x_min,x_max),
(y,y_min,y_max)
)
)
my_plot.show()
Currently, when SymPy calls contour(), it does not appear to be saving the returned ContourSet (Update: I have filed a issue to see if the ContourSet can be saved):
class MatplotlibBackend(BaseBackend):
...
def process_series(self):
...
for s in self.parent._series:
# Create the collections
...
elif s.is_contour:
self.ax.contour(*s.get_meshes()) # returned ContourSet not saved by SymPy
In other examples where modifications are performed to the plot, such as adding inline labels using clabel(), the ContourSet (CS) is needed:
# Create a simple contour plot with labels using default colors.
plt.figure()
CS = plt.contour(X, Y, Z) # CS is the ContourSet
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
Going back to the SymPy example, my_plot._backend does provide access to the figure and axes; what workarounds are possible to keep or obtain access to the ContourSet?
One option when SymPy's built-in plotting capabilities fall short of what you want is to use matplotlib directly. The key is to use lambdify to convert the SymPy expression to a NumPy function.
f = lambdify((x, y), sqrt(x**2 + y**2), 'numpy')
The following creates a contour plot, with c as the ContourSet object.
a = numpy.linspace(-7, 7, 1000)
b = numpy.linspace(-5, 5, 1000)
x, y = numpy.meshgrid(a, b)
c = matplotlib.pyplot.contour(x, y, f(x, y))
In this question you learn that you need to keep a reference to your contour plot, from which you can retrieve the points. For your 'Simplest default with labels', CS.collections[0].get_paths().
But I can't find a way to retrieve the list of plots from a given axes object...
In the following code C contains the desired collection of lines, but one collection per level in the contour plot and with some scaling:
import numpy as np
import matplotlib.pylab as plt
X = np.arange(10)
Y = np.arange(10)
Z = np.random.random((10,10))
fig = plt.figure()
ax = fig.add_subplot(111)
A = ax.get_children()
cs = ax.contour (X, Y, Z)
B = ax.get_children()
C = [ref for ref in B if ref not in A]
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.add_collection(C[0])
Which results in fig:
and fig2:

how can I plot on the axes

I actually want to recreate an image like the following:
Specially the little X on the xaxes
I have a
list = [[100,-3],[200,None],[120,-2] ... ]
and I do
for x in list:
if x[1]!=None:
plot(x[0],x[1],'ok')
else:
### PLot on the axes ###
But while I am plotting I do not know what the axes are. I know that some values are None, for example ( 250,None), So I want to plot on the xaxes at x = 250, but I have not idea what eventually the min(ylim()) will be.
I know I can do plot(250,-5,'X',zorder=999999) but this is only when I know what the min axes is.. (I can not do min, max and so to know the min axes. as the real data is a list inside a list inside a dictionary etc.. )
So the trick is to use a custom transformation. The regular data transformation for the x axis and the axes transformation for the y axis. Matplotlib calls that a blended transformation, which you need to create yourself. You'll find more information in this awesome guide.
And as #ThePredator already pointed out, you have to set clip_on=False, otherwise your markers will be clipped.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
fig, ax = plt.subplots()
# the x coords of this transformation are data, and the
# y coord are axes
trans = transforms.blended_transform_factory( ax.transData, ax.transAxes)
# data points on the axes
x = np.random.rand(5)*100. + 200.
y = [0]*5
ax.plot(x, y, 'kx', transform=trans, markersize=10, markeredgewidth=2,
clip_on=False)
# regular data
x = np.random.rand(5)*100. + 200.
y = np.random.rand(5)*100. + 200.
ax.plot(x, y, 'ro')
plt.show()
Result:
You can use the clip_on = False option. Example:
In your case, you can set your y limits.
Example:
x = [0,1,2,3,4,5]
y = [0,0,0,0,0,0]
plt.plot(x,y,'x',markersize=20,clip_on=False,zorder=100)
plt.ylim(0,1)
plt.show()
You can use get_ylim() in order to get the position of the axis and then plot on it.

Contourf animation

I am using a for loop to calculate values at every node of 20x20 matrix and storing data in
MM = []
I want to animate the results and my code looks like this:
ax = plt.subplot(111)
for i in range(60):
x = MM[i]
ax.contourf(X,Y,x, cmap = cm.hot)
plt.draw()
plt.show()
The problem is that it shows only MM[-1].
I have looked over the examples given here, but can't figure out how to make it work.
Thank you.
Your problem is likely due how you are running Matplotlib and what graphical backend you are using. The following example works in IPython. Note that I call ion() to set the interactive mode to on.
from matplotlib import pyplot as plt
import numpy as np
x = y = np.arange(-3.0, 3.01, 0.025)
X, Y = np.meshgrid(x, y)
plt.ion()
ax = plt.subplot(111)
for i in range(1,20):
Z1 = plt.mlab.bivariate_normal(X, Y, 0.5+i*0.1, 0.5, 1, 1)
ax.contourf(x,y,Z1, cmap = plt.cm.hot)
plt.draw()
plt.show()
The information here should help you get your animation running.

Categories