No exponential form of the z-axis in matplotlib-3D-plots - python

I have a similar problem as described in How to prevent numbers being changed to exponential form in Python matplotlib figure:
I don't want that (in my special case) weird scientific formatting of the axis. My problem is different as I have this problem at my z-Axis. For 2-D plots I can use ax.get_yaxis().get_major_formatter().set_useOffset(False). And there is no function ax.get_zaxis()
What do I use to format my z-Axis the same way?
EDIT: Example:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import sys
import matplotlib
import matplotlib.pyplot as pyplot
def func(xi, ti):
res = 10e3 + np.cos(ti) * np.sin(xi)
return res
if __name__ == '__main__':
timeSpacing = 20
timeStart = 0
timeEnd = 1
time = np.linspace(timeStart, timeEnd, timeSpacing)
widthSpacing = 50
widthStart = 0
widthEnd = 3
width = np.linspace(widthStart, widthEnd, widthSpacing)
resList = []
matplotlib.rcParams['legend.fontsize'] = 10
fig = pyplot.figure()
ax = fig.gca(projection = '3d')
for i, item in enumerate(time):
ti = [item for t in width]
res = func(width, ti)
ax.plot(width, ti, res, 'b')
ax.set_xlabel('x')
ax.set_ylabel('t')
ax.set_zlabel('f(x,t)')
pyplot.show()

As you say, there is no get_zaxis() method. But, fortunately, there is zaxis field (so don't add ()). There are also xaxis and yaxis fields, so you can use all of those uniformly instead of get_...axis() if you like.
For example:
if __name__ == '__main__':
...
ax = fig.gca(projection = '3d')
ax.zaxis.get_major_formatter().set_useOffset(False) # here
for i, item in enumerate(time):
...
and the end result should look something like this:
As you can see, for large numbers it might not look so well...

Related

Matplotlib how to move axis along data in a real-time animation

I'm trying to plot data that is generated in runtime. In order to do so I'm using matplotlib.animation.FuncAnimation.
While the data is displayed correctly, the axis values are not updating accordingly to the values that are being displayed:
The x axis displays values from 0 to 10 eventhough I update them in every iteration in the update_line function (see code below).
DataSource contains the data vector and appends values at runtime, and also returns the indexes of the values being returned:
import numpy as np
class DataSource:
data = []
display = 10
# Append one random number and return last 10 values
def getData(self):
self.data.append(np.random.rand(1)[0])
if(len(self.data) <= self.display):
return self.data
else:
return self.data[-self.display:]
# Return the index of the last 10 values
def getIndexVector(self):
if(len(self.data) <= self.display):
return list(range(len(self.data)))
else:
return list(range(len(self.data)))[-self.display:]
I've obtained the plot_animation function from the matplotlib docs.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from datasource import DataSource
def update_line(num, source, line):
data = source.getData()
indexs = source.getIndexVector()
if indexs[0] != 0:
plt.xlim(indexs[0], indexs[-1])
dim=np.arange(indexs[0],indexs[-1],1)
plt.xticks(dim)
line.set_data(indexs,data)
return line,
def plot_animation():
fig1 = plt.figure()
source = DataSource()
l, = plt.plot([], [], 'r-')
plt.xlim(0, 10)
plt.ylim(0, 1)
plt.xlabel('x')
plt.title('test')
line_ani = animation.FuncAnimation(fig1, update_line, fargs=(source, l),
interval=150, blit=True)
# To save the animation, use the command: line_ani.save('lines.mp4')
plt.show()
if __name__ == "__main__":
plot_animation()
How can I update the x axis values in every iteration of the animation?
(I appreciate suggestions to improve the code if you see any mistakes, eventhough they might not be related to the question).
Here is a simple case of how you can achieve this.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
%matplotlib notebook
#data generator
data = np.random.random((100,))
#setup figure
fig = plt.figure(figsize=(5,4))
ax = fig.add_subplot(1,1,1)
#rolling window size
repeat_length = 25
ax.set_xlim([0,repeat_length])
ax.set_ylim([-2,2])
#set figure to be modified
im, = ax.plot([], [])
def func(n):
im.set_xdata(np.arange(n))
im.set_ydata(data[0:n])
if n>repeat_length:
lim = ax.set_xlim(n-repeat_length, n)
else:
lim = ax.set_xlim(0,repeat_length)
return im
ani = animation.FuncAnimation(fig, func, frames=data.shape[0], interval=30, blit=False)
plt.show()
#ani.save('animation.gif',writer='pillow', fps=30)
Solution
My problem was in the following line:
line_ani = animation.FuncAnimation(fig1, update_line, fargs=(source, l),
interval=150, blit=True)
What I had to do is change the blit parameter to False and the x axis started to move as desired.

Python FuncAnimation is not updating the frame when I am trying to update 4 plots in a subplot

I am a newbie and trying to get the basics of Python right. I am trying to create an animation with 4 plots using matplotlib.pyplot.subplots. Each plot has same mean but different standard deviation. Here's my code:
import numpy as np
import matplotlib as mlp
import matplotlib.animation as animation
Test data
n = 100
mn = 0
stdv = [1,2,3,4]
x = [np.random.normal(loc= mn, scale = stdv[0], size = n ),
np.random.normal(loc= mn, scale = stdv[1], size = n ),
np.random.normal(loc= mn, scale = stdv[2], size = n ),
np.random.normal(loc= mn, scale = stdv[3], size = n )]
Animation update function
def anim_norm(i):
if (i == n):
b.event_source.stop()
plt.cla()
ax = [ax1,ax2,ax3,ax4]
for k in range((len(ax)+1)):
ax[k].set_title('S.D. = {}, n = {}'.format(stdv[k],i))
ax[k].set_xlabel('Value')
ax[k].set_ylabel('Frequency')
ax[k].hist(x[k][:i])
Running the animation
fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2, sharex = True)
b = animation.FuncAnimation(fig,anim_norm, interval = 300)
All I see is the plots with xlabel, ylabel, and title and the first frame. I would appreciate any guidance. Also, do I need to increment (i - the frame count) or FuncAnimation does it automatically?
Thank you!

Matplotlib: how to update the figure title after user has zoomed?

Is there any way to update the title of a Matplotlib figure after the user has zoomed in? For example, I would like the title to display the exact extends of the x-axis,
import pylab as pl
import numpy as np
x = np.arange(10,step=0.1)
y = np.sin(x)
f = pl.figure()
pl.plot(x,y)
def my_ondraw(ev):
x1,x2 = f.gca().get_xlim() # FIXME value hasn't been updated yet
pl.title("x = [%f, %f]" % (x1,x2))
f.canvas.mpl_connect('draw_event', my_ondraw)
pl.show()
As noted, my code doesn't get the right values back from get_xlim() because the re-draw hasn't been done at the time my_ondraw is called...
Any suggestions?
Modified code that works based on Ilya's suggestion below:
import pylab as pl
import numpy as np
x = np.arange(10,step=0.1)
y = np.sin(x)
f = pl.figure()
ax = f.gca()
pl.plot(x,y)
def my_ondraw(ev):
print "my_ondraw: %s" % ev.name
x1,x2 = f.gca().get_xlim() # FIXME value hasn't been updated yet
pl.title("x = [%f, %f]" % (x1,x2))
ax.callbacks.connect('xlim_changed', my_ondraw)
pl.show()
You can register callback functions on the xlim_changed and ylim_changed events. Try something like this:
def on_xylims_change(axes):
x1,x2 = f.gca().get_xlim() # FIXME value hasn't been updated yet
pl.title("x = [%f, %f]" % (x1,x2))
fig, ax = pl.subplots(1, 1)
ax.callbacks.connect('xlim_changed', on_xylims_change)
ax.callbacks.connect('ylim_changed', on_xylims_change)
You can read more about it here: Event handling and picking in Matplotlib.

producing histogram with y axis as relative frequency?

Today my task is to produce a histogram where the y axis is a relative frequency rather than just an absolute count. I've located another question regarding this (see: Setting a relative frequency in a matplotlib histogram) however, when I try to implement it, I get the error message:
'list' object has no attribute size
despite having the exact same code given in the answer -- and despite their information also being stored in a list.
In addition, I have tried the method here(http://www.bertplot.com/visualization/?p=229) with no avail, as the output still doesn't show the y label as ranging from 0 to 1.
import numpy as np
import matplotlib.pyplot as plt
import random
from tabulate import tabulate
import matplotlib.mlab as mlab
precision = 100000000000
def MarkovChain(n,s) :
"""
"""
matrix = []
for l in range(n) :
lineLst = []
sum = 0
crtPrec = precision
for i in range(n-1) :
val = random.randrange(crtPrec)
sum += val
lineLst.append(float(val)/precision)
crtPrec -= val
lineLst.append(float(precision - sum)/precision)
matrix2 = matrix.append(lineLst)
print("The intial probability matrix.")
print(tabulate(matrix2))
baseprob = []
baseprob2 = []
baseprob3 = []
baseprob4 = []
for i in range(1,s): #changed to do a range 1-s instead of 1000
#must use the loop variable here, not s (s is always the same)
matrix_n = np.linalg.matrix_power(matrix2, i)
baseprob.append(matrix_n.item(0))
baseprob2.append(matrix_n.item(1))
baseprob3.append(matrix_n.item(2))
baseprob = np.array(baseprob)
baseprob2 = np.array(baseprob2)
baseprob3 = np.array(baseprob3)
baseprob4 = np.array(baseprob4)
# Here I tried to make a histogram using the plt.hist() command, but the normed=True doesn't work like I assumed it would.
'''
plt.hist(baseprob, bins=20, normed=True)
plt.show()
'''
#Here I tried to make a histogram using the method from the second link in my post.
# The code runs, but then the graph that is outputted isn't doesn't have the relative frequency on the y axis.
'''
n, bins, patches = plt.hist(baseprob, bins=30,normed=True,facecolor = "green",)
y = mlab.normpdf(bins,mu,sigma)
plt.plot(bins,y,'b-')
plt.title('Main Plot Title',fontsize=25,horizontalalignment='right')
plt.ylabel('Count',fontsize=20)
plt.yticks(fontsize=15)
plt.xlabel('X Axis Label',fontsize=20)
plt.xticks(fontsize=15)
plt.show()
'''
# Here I tried to make a histogram using the method seen in the Stackoverflow question I mentioned.
# The figure that pops out looks correct in terms of the axes, but no actual data is posted. Instead the error below is shown in the console.
# AttributeError: 'list' object has no attribute 'size'
fig = plt.figure()
ax = fig.add_subplot(111)
ax.hist(baseprob, weights=np.zeros_like(baseprob)+1./ baseprob.size)
n, bins, patches = ax.hist(baseprob, bins=100, normed=1, cumulative=0)
ax.set_xlabel('Bins', size=20)
ax.set_ylabel('Frequency', size=20)
ax.legend
plt.show()
print("The final probability matrix.")
print(tabulate(matrix_n))
matrixTranspose = zip(*matrix_n)
evectors = np.linalg.eig(matrixTranspose)[1][:,0]
print("The steady state vector is:")
print(evectors)
MarkovChain(5, 1000)
The methods I tried are each commented out, so to reproduce my errors, make sure to erase the comment markers.
As you can tell, I'm really new to Programming. Also this is not for a homework assignment in a computer science class, so there are no moral issues associated with just providing me with code.
The expected input to matplotlib functions are usually numpy arrays, which have the methods nparray.size. Lists do not have size methods so when list.size is called in the hist function, this causes your error. You need to convert, using nparray = np.array(list). You can do this after the loop where you build the lists with append, something like,
baseprob = []
baseprob2 = []
baseprob3 = []
baseprob4 = []
for i in range(1,s): #changed to do a range 1-s instead of 1000
#must use the loop variable here, not s (s is always the same)
matrix_n = numpy.linalg.matrix_power(matrix, i)
baseprob.append(matrix_n.item(0))
baseprob2.append(matrix_n.item(1))
baseprob3.append(matrix_n.item(2))
baseprob = np.array(baseprob)
baseprob2 = np.array(baseprob2)
baseprob3 = np.array(baseprob3)
baseprob4 = np.array(baseprob4)
EDIT: minimal hist example
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
baseprob = np.random.randn(1000000)
ax.hist(baseprob, weights=np.zeros_like(baseprob)+1./ baseprob.size, bins=100)
n, bins, patches = ax.hist(baseprob, bins=100, normed=1, cumulative=0, alpha = 0.4)
ax.set_xlabel('Bins', size=20)
ax.set_ylabel('Frequency', size=20)
ax.legend
plt.show()
which gives,

Can i put a color changer in a loop?

So basically what i'm wondering, is at the bottom of my code when i plot the graph of my trials, is there a way to run a color generator through there? Or more explicitly put, could i make a list of warm colors, and put that into my plot function, where it runs through each color in a list as the loop runs through, and therefore my plot would only consist of warm colors?
from numpy import *
from pylab import show,plot
from scipy.special import erfinv
n = 366 #number of days
ntrials = 5000
u = random.rand(ntrials)
v = sqrt(2.)*erfinv(2.*u-1.)
mu = 0
sigma = .05
investment = 1000.
data = empty((ntrials,n))
data[:,0] = investment
for t in range(n-1):
u = random.rand(ntrials)
v = sqrt(2.)*erfinv(2.*u-1.)
epsilon = v
data[:,t+1] = (1. + mu +sigma*epsilon)*data[:,t]
data2 = data.sum(axis=0)
woo = data2[-1]/ntrials
data3 = data2[-1]
x = linspace(0,n,n)
for t in range(n):
plot(x,data[t,:])
show()
It sounds like you just want something like this?
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
# Generate data...
nx, nsteps = 100, 20
x = np.linspace(0, 1, nx)
data = np.random.random((nx, nsteps)) - 0.5
data = data.cumsum(axis=0)
data = data.cumsum(axis=1)
# Plot
cmap = mpl.cm.autumn
for i, y in enumerate(data.T):
plt.plot(x, y, color=cmap(i / float(nsteps)))
plt.show()
The key is that calling a matplotlib colormap instance with a value between 0 and 1 will return a color (where 0 is the lowest color in the colormap and 1 is the highest).
For a list of available colormaps, see here. You can access the reversed version of any of these with name_r (e.g. the reversed version of mpl.cm.autumn is mpl.cm.autumn_r).

Categories