matplotlib subplot not working as expected - python-2.7

I have the following code:
import matplotlib.pyplot as plt
horas = [1,2,3,4]
diccionario = {(1,1,2,1):[2,3,4,5],
(1,2,2,2):[2,5,1,5],
(1,3,2,3):[2,5,5,5],
(1,4,2,4):[2,6,8,5],
(1,5,2,5):[2,7,5,5],
(1,6,2,6):[2,8,2,5],
(1,7,2,7):[2,9,6,5],
(1,8,2,8):[2,4,9,5]}
plt.figure()
i = 1
maximo = 0
keys = diccionario.keys()
for n in range(0,len(keys)-1,2):
gn, = plt.plot(horas,diccionario[keys[n]],'ro-')
gn1, = plt.plot(horas,diccionario[keys[n+1]],'g*-')
plt.subplot(len(keys)//2, 1,i)
plt.legend([gn,gn1], [keys[n],keys[n+1]])
i+=1
plt.show()
I expect to have 4 subplots with two lines each. I have them, but the last one is empty.
Could anyone explain why? I have tried many different ways without succeeding.

Put your subplot() before you plot gn and gn1. That will solve your problem.
for n in range(0, len(keys) - 1,2):
plt.subplot(len(keys)//2, 1, i)
gn, = plt.plot(horas, diccionario[keys[n]], 'ro-')
gn1, = plt.plot(horas, diccionario[keys[n+1]], 'g*-')
plt.legend([gn, gn1], [keys[n], keys[n+1]])
i+=1
By the way, I recommend to use tuple instead of dict. You may notice that the sequence of results is quite different from what you want.

Related

add multiple colorbars to a subplot of polar contourf [duplicate]

I would like to add a separate colorbar to each subplot in a 2x2 plot.
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
plt.colorbar(z1_plot,cax=ax1)
z2_plot = ax2.scatter(x,y,c = z2,vmin=0.0,vmax=40)
plt.colorbar(z1_plot,cax=ax2)
z3_plot = ax3.scatter(x,y,c = z3,vmin=0.0,vmax=894)
plt.colorbar(z1_plot,cax=ax3)
z4_plot = ax4.scatter(x,y,c = z4,vmin=0.0,vmax=234324)
plt.colorbar(z1_plot,cax=ax4)
plt.show()
I thought that this is how you do it, but the resulting plot is really messed up; it just has an all grey background and ignores the set_xlim , set_ylim commands I have (not shown here for simplicity). + it shows no color bars. Is this the right way to do it?
I also tried getting rid of the "cax = ...", but then the colorbar all goes on the bottom right plot and not to each separate plot!
This can be easily solved with the the utility make_axes_locatable. I provide a minimal example that shows how this works and should be readily adaptable:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
m1 = np.random.rand(3, 3)
m2 = np.arange(0, 3*3, 1).reshape((3, 3))
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(121)
im1 = ax1.imshow(m1, interpolation='None')
divider = make_axes_locatable(ax1)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im1, cax=cax, orientation='vertical')
ax2 = fig.add_subplot(122)
im2 = ax2.imshow(m2, interpolation='None')
divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im2, cax=cax, orientation='vertical');
In plt.colorbar(z1_plot,cax=ax1), use ax= instead of cax=, i.e. plt.colorbar(z1_plot,ax=ax1)
Specify the ax argument to matplotlib.pyplot.colorbar(), e.g.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2)
for i in range(2):
for j in range(2):
data = np.array([[i, j], [i+0.5, j+0.5]])
im = ax[i, j].imshow(data)
plt.colorbar(im, ax=ax[i, j])
plt.show()
Please have a look at this matplotlib example page. There it is shown how to get the following plot with four individual colorbars for each subplot:
I hope this helps.
You can further have a look here, where you can find a lot of what you can do with matplotlib.
Try to use the func below to add colorbar:
def add_colorbar(mappable):
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
last_axes = plt.gca()
ax = mappable.axes
fig = ax.figure
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = fig.colorbar(mappable, cax=cax)
plt.sca(last_axes)
return cbar
Then you codes need to be modified as:
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
add_colorbar(z1_plot)

Lmfit separate peak fitting

I'm very new to curve/peak fitting, but I am trying to fit a data set with multiple separate independent peaks. I've tried something similar to the example provided by lmfit, and here's my code:
import matplotlib.pyplot as plt
from lmfit.models import GaussianModel
from numpy import loadtxt
data = loadtxt('079-55.freq')
x = data[:, 0]
y = data[:, 1]
gauss1 = GaussianModel(prefix='g1_')
pars = gauss1.make_params()
pars['g1_center'].set(4100, min=2000, max=4500)
pars['g1_amplitude'].set(170, min=10)
gauss2 = GaussianModel(prefix='g2_')
pars.update(gauss2.make_params())
pars['g2_center'].set(4900, min=4500, max=5500)
pars['g2_amplitude'].set(30, min=10)
gauss3 = GaussianModel(prefix='g3_')
pars.update(gauss3.make_params())
pars['g3_center'].set(600, min=5500, max=10000)
pars['g3_amplitude'].set(13, min=10)
mod = gauss1 + gauss2 + gauss3
init = mod.eval(pars, x=x)
plt.plot(x, init, 'k--')
out = mod.fit(y, pars, x=x)
print(out.fit_report())
plt.plot(x, out.best_fit, 'r-')
plt.plot(x, y)
plt.show()
However, the result becomes something like this:
I am very confused as to how to proceed to fit three separate peaks as shown below. I think the parameter update is for pitting multiple model into the same data set, not for separate independent peaks. I could be wrong though. Is there any suggestions?
pars['g3_center'].set(600, min=5500, max=10000)
Probably confuses the parameter or model class as 600 is not within the bounds of min and max.

Categorical Mixture Model in Pymc3

I'm new to Pymc3 and I'm trying to create the Categorical Mixture Model shown in https://en.wikipedia.org/wiki/Mixture_model#Categorical_mixture_model . I'm having difficulty hooking up the 'x' variable. I think it's because I have to make the z variable Deterministic, but I'm getting an error message at the line where 'x' is assigned : "ValueError: We expected 3 inputs but got 2.". It looks like the p function only accepts 2 inputs so I'm stuck. I've tried a bunch of different things, but haven't been able to get this to work yet.
import numpy as np
from pymc3 import *
import theano.tensor as t
K = 3 #NUMBER OF TOPICS
V = 20 #NUMBER OF WORDS
N = 15 #NUMBER OF DOCUMENTS
#GENERAETE RANDOM CATEGORICAL MIXTURES
data = np.ones([N,V])
#theano.compile.ops.as_op(itypes=[t.lscalar, t.dscalar, t.dscalar],otypes=[t.dvector])
def p(z=z, phi=phi):
return [phi[z[i,j]] for i in range(D) for j in range(W)]
model = Model()
with model:
alpha = np.ones(V)
beta = np.ones(K)
theta = [Dirichlet('theta_%i' % i, alpha, shape=V) for i in range(K)]
phi = Dirichlet('phi', beta, shape=K)
z = [Categorical('z_%i' % i, p = phi, shape=V) for i in range(N)]
x = [Categorical('x_%i_%i' % (i,j), p=p(z[i][j],phi), observed=data[i,j]) for i in range(N) for j in range(V)]
#x = [Categorical('x_%i_%i' % (i,j), p=theta[z[i][j]], observed=data[i,j]) for i in range(N) for j in range(V)]
print "Created model. Now begin sampling"
step = Slice()
trace = sample(n, step)
trace.get_values('phi')
For starters, in your example above, z and phi have no value which would allow them to be used as default values. We also don't have values for D and W.
As for the number of arguments, the function you define has 2 but your theano decorator above it has 3. I'd suggest
#theano.compile.ops.as_op(itypes=[t.lscalar, t.dvector],otypes=[t.dvector])
def p(z, phi):
return [phi[z[i,j]] for i,j in zip(range(D),range(W))]

Iterating operations over unique values of an array

I have a pandas dataframe that resembles one generated as follows.
import numpy as np
import pandas as pd
x0 = pd.DataFrame(np.random.normal(size=(10, 4)))
x1 = pd.DataFrame({'x': [1,1,2,3,2,3,4,1,2,3]})
df = pd.concat((x0, x1), axis=1)
and a function:
def fun(df, n=100):
z = np.random.normal(size=n)
return np.dot(df[[0,1,2,3]], [0.5*z,-1*z,0.3*z,1.2*z])
I would like to:
use identical draws z for each unique value in x,
take the product of the output in the above step over items of unique x
Any suggestion?
Explanation:
Generate n=100 draws to get z such that len(z)=100
For each elem in z, evaluate the function fun,
For i in df.x.unique(), compute the product of the output in step (2) element-wise. I am expecting to get a DataFrame or array of dimension (len(df.x.unique(), n=100)
4.
It sounds like you want to group by 'x', taking one of its instances (let's assume we take the first one observed).
just call your function as follows:
f = fun(df.groupby('x').first())
>>> f.shape
Out[25]: (4, 100)
>>> len(df.x.unique()
Out[26]: 4

AttributeError: 'numpy.flatiter' object has no attribute 'get_offsets' in python

In a scatter plot matrix, I would like to draw a region in every subplot and print the points that are included in the region. I found the LassoSelector widget, which does exactly that. I am trying to extend its functionality for more than one subplots. I am getting the following error: self.xys = collection.get_offsets(),
AttributeError: 'numpy.flatiter' object has no attribute 'get_offsets'.
when the line selector = SelectFromCollection(axes, ax.flat) is in the for loop, and I am getting the error: self.canvas = ax.figure.canvas,AttributeError: 'numpy.ndarray' object has no attribute 'figure' when the line selector = SelectFromCollection(ax, ax.flat) is outside of the loop. Why does this happen?
Here is my code:
from __future__ import print_function
import numpy as np
from matplotlib.widgets import LassoSelector
from matplotlib.path import Path
class SelectFromCollection(object):
"""Select indices from a matplotlib collection using `LassoSelector`.
Selected indices are saved in the `ind` attribute. This tool highlights
selected points by fading them out (i.e., reducing their alpha values).
If your collection has alpha < 1, this tool will permanently alter them.
Note that this tool selects collection objects based on their *origins*
(i.e., `offsets`).
Parameters
----------
ax : :class:`~matplotlib.axes.Axes`
Axes to interact with.
collection : :class:`matplotlib.collections.Collection` subclass
Collection you want to select from.
alpha_other : 0 <= float <= 1
To highlight a selection, this tool sets all selected points to an
alpha value of 1 and non-selected points to `alpha_other`.
"""
def __init__(self, ax, collection, alpha_other=0.3):
self.canvas = ax.figure.canvas
self.collection = collection
self.alpha_other = alpha_other
self.xys = collection.get_offsets()
self.Npts = len(self.xys)
# Ensure that we have separate colors for each object
self.fc = collection.get_facecolors()
if len(self.fc) == 0:
raise ValueError('Collection must have a facecolor')
elif len(self.fc) == 1:
self.fc = np.tile(self.fc, self.Npts).reshape(self.Npts, -1)
self.lasso = LassoSelector(ax, onselect=self.onselect)
self.ind = []
def onselect(self, verts):
path = Path(verts)
self.ind = np.nonzero([path.contains_point(xy) for xy in self.xys])[0]
self.fc[:, -1] = self.alpha_other
self.fc[self.ind, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
print(selector.xys[selector.ind])
#selector.disconnect()
def disconnect(self):
self.lasso.disconnect_events()
self.fc[:, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
if __name__ == '__main__':
import matplotlib.pyplot as plt
plt.ion()
data=np.loadtxt(r"data.txt")
x = data[:, 3]
x1 = data[:, 4]
y = data[:,5]
y1 = data[:,6]
fig, ax = plt.subplots(nrows=2, ncols=2, squeeze=True)
for axes, marker in zip(ax.flat, ['o', 'o']):
ax.flat[0].plot(x, y, 'r', ls='', marker=marker)
ax.flat[1].plot(x, x1,'r', ls='', marker=marker)
ax.flat[2].plot(x, y1,'r', ls='', marker=marker)
ax.flat[3].plot(y, x1,'r', ls='', marker=marker)
selector = SelectFromCollection(ax, ax.flat)
plt.show(block=True)
plt.draw()
Ok, I found a few problems that are causing your code not to work properly. There we go:
Firts of all, you modified the SelectFromCollection class that you got from the LassoSelector example to print every selected point, but forgot a detail:
class SelectFromCollection(object):
def __init__(self, ax, collection, alpha_other=0.3):
# ...
# No changes here...
# ...
def onselect(self, verts):
path = Path(verts)
self.ind = np.nonzero([path.contains_point(xy) for xy in self.xys])[0]
self.fc[:, -1] = self.alpha_other
self.fc[self.ind, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
print(self.xys[self.ind]) # <- THIS LINE HAS CHANGED!!!
#selector.disconnect()
def disconnect(self):
# ...
# No changes here...
# ...
Now you can use multiple instances of SelectFromCollection.
Then, you are also creating only one instance of SelectFromCollection (so only one subplot would react). Furthermore, according to the doctsring the second argument the __init__ method expects is a matplotlib.collections.Collection instance.
Instead you are passing it a numpy array (in fact a numpy.Flatiter) that contains two Axes instances. If you look at the example, there it gets a Collection instance returned by the scattercommand (they use scatter instead of plot).
All in all, and restiling the loop, this is my version
if __name__ == '__main__':
import matplotlib.pyplot as plt
data=np.random.rand(3,100)
xdata = data[:-1] # all rows but last
y = data[-1] # last row
fig, axes = plt.subplots(nrows=1, ncols=2, squeeze=True)
markers = ['o','^']
selectors =[]
for i in xrange(xdata.shape[0]):
pts = axes[i].scatter(xdata[i], y, c='r', marker=markers[i])
selectors.append(SelectFromCollection(axes[i], pts))
plt.show()
EDIT
If you want to do more plots, it is not hard. You can try to write more synthetic code with a for loop and so on, but an easier solution is to write directly the repetitions of the code:
if __name__ == '__main__':
import matplotlib.pyplot as plt
data=np.loadtxt(r"data.txt")
x = data[:, 3]
x1 = data[:, 4]
y = data[:,5]
y1 = data[:,6]
fig, axes = plt.subplots(nrows=2, ncols=2)
pts1 = axes[0,0].scatter(x, y, c='r', marker='o')
select1 = SelectFromCollection(axes[0,0], pts1)
pts2 = axes[1,0].scatter(x, x1, c='r', marker='o')
select2 = SelectFromCollection(axes[1,0], pts2)
pts3 = axes[0,1].scatter(x, y1, c='r', marker='o')
select3 = SelectFromCollection(axes[0,1], pts3)
pts4 = axes[1,1].scatter(y, x1, c='r', marker='o')
select4 = SelectFromCollection(axes[1,1], pts4)
plt.show()
Still, it is necessary that you change the definition of the SelectFromCollection class as I said above.