Python - figure settings in plotting loop - python

Hi
I have a little problem, I made a loop which creates 3 plots in every iteration and set text
on x label to be rotated but it works only for last fig in a row. I am not sure how to affect first and second figure.
def multi_scatter(x_list, y):
sns.set(style='whitegrid', rc={"grid.linewidth": 0.2})
sns.set_context("paper", font_scale=2)
for x in range(0, len(x_list)):
if x == 0 or x % 3:
chart = sns.pairplot(data=ds_train,
y_vars=[y],
x_vars=[x_list[x], x_list[x+1], x_list[x+2]],
height = 10)
plt.xticks(rotation = 45)
plt.show()
else:
continue
Thank You in advance

This is becuase you defined chart but never extract the axes from chart. You need to specify what the axes are in order to set xticklabels. Try to add these lines in your code (see the inner for loop):
def multi_scatter(x_list, y):
sns.set(style='whitegrid', rc={"grid.linewidth": 0.2})
sns.set_context("paper", font_scale=2)
for x in range(0, len(x_list)):
if x == 0 or x % 3:
chart = sns.pairplot(data=ds_train,
y_vars=[y],
x_vars=[x_list[x], x_list[x+1], x_list[x+2]],
height = 10)
for ax in chart.axes.flat:
ax.tick_params(axis='x', labelrotation=45 )
else:
continue
I did not test it without access to your data, so please let me know if it works!

Related

Trying to plot animation in Python using Matplotlib

Good morning all,
I have been working on a small personal project, but am now stuck in the final plotting phase.
So far, I have created a 4 dimensional array called "colored_map":
dimension 1: frame number (0-499) which I'm trying to iterate over
dimension 2 and 3: x and y positions
dimension 4: RGB values of each element
In short, I am trying to plot each frame by iterating over the first dimension of the array, and clear the plot after each iteration so the output looks like a "video".
I have tried the following piece of code, but it does not replace/ overwrite the previous fig:
for j in range(0,500):
img = colored_map[j]
fig = plt.figure(figsize = (5,5))
#ax = fig.add_subplot(111)
#ax.set_axis_off()
plt.clf()
plt.imshow(img)
plt.pause(1)
I also tried the below piece of code which I found somewhere else, but it only creates the first frame:
#Setting up the figure and axes
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(111)
ax.set_axis_off()
im = ax.imshow(colored_map[0])
#Animate function to iterate over successive frames
def animate(i):
im.set_data(colored_map[i])
return im
#Calling the animator to put the different frames together
anim = animation.FuncAnimation(fig, animate, frames=500, interval=20)
plt.show()
You can create the colored_map array using the following piece of code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, colors
density = 0.8
prob = 0.9
#You could reduce n_iterations (= 1st dim) and forest_size (2nd and 3rd dim) to create an smaller array
n_iterations = 200
forest_size = [101,101]
black = [0,0,0]
green = [0,153,0]
orange = [255,128,0]
states = np.zeros((n_iterations,forest_size[0],forest_size[1]))
states[0] = np.random.choice([0,1],forest_size,p=[1-density, density])
states[0,np.random.randint(1,forest_size[0]-2),np.random.randint(1,forest_size[1]-2)] = 2
for i in range(1,n_iterations):
states[i]=states[i-1].copy()
for x in range(1, forest_size[0]-1):
for y in range(1, forest_size[1]-1):
if states[i-1,x,y]==2:
states[i,x,y]=0
states[i,x+1,y]= np.random.choice([1,2],1,p=[1-prob,prob])[0]
if states[i-1,x-1,y]==1:
states[i,x-1,y]= np.random.choice([1,2],1,p=[1-prob,prob])[0]
if states[i-1,x,y+1]==1:
states[i,x,y+1]= np.random.choice([1,2],1,p=[1-prob,prob])[0]
if states[i-1,x,y-1]==1:
states[i,x,y-1]= np.random.choice([1,2],1,p=[1-prob,prob])[0]
colored_map = np.zeros((n_iterations,forest_size[0],forest_size[1],3),dtype=np.uint8)
for i in range(0,colored_map.shape[0]):
for x in range(0,colored_map.shape[1]):
for y in range(0,colored_map.shape[2]):
cur_value = states[i,x,y].copy()
if cur_value == 0:
colored_map[i,x,y] = black
if cur_value == 1:
colored_map[i,x,y] = green
if cur_value == 2:
colored_map[i,x,y] = orange
Can someone please help me by pointing out what I'm doing wrong here?
Thank you in advance for your help!

Limit the Number of Open Matplotlib Figures in Python 3

I have a small python 3 script:
import matplotlib.pyplot as plt;
i = 0;
while(i < 40):
x = [1,2,3,4,5];
y = [1,2,3,4,5];
fig = plt.figure();
grid = plt.GridSpec(1, 1)
axis = fig.add_subplot(grid[0,0]);
axis.bar(x,y);
fig.canvas.flush_events()
while(len(plt.get_fignums()) > 10):
pass;
plt.show(block=False);
i += 1;
My goal is to plot 40 plots. I want the first 10 to plot immediately, and then the next figures will only plot if one of the open 10 plots are closed, one by one. This script seems to almost achieve what I want to do, but it crashes when I try to close one of the first 10 plots. Why does this happen? Thanks
while loop is not proper idea for this situation, your code should listens for close event of figures, then act as desired. these few lines of code may help you:
import matplotlib.pyplot as plt;
desiredNumberOfPlots_initialPopulation=1
desiredNumberOfPlots_total=3
def figOnce():
x = [1,2,3,4,5];
y = [1,2,3,4,5];
fig = plt.figure();
grid = plt.GridSpec(1, 1)
axis = fig.add_subplot(grid[0,0]);
axis.bar(x,y);
fig.canvas.flush_events()
fig.canvas.mpl_connect('close_event', handle_close)
plt.show(block=False);
global desiredNumberOfPlots_total
desiredNumberOfPlots_total-=1
def handle_close(evt):
global desiredNumberOfPlots_total
if desiredNumberOfPlots_total>0:
figOnce()
i=1
while(i<=desiredNumberOfPlots_initialPopulation):
print(i)
i+=1
figOnce()

How to save multiple plots in a folder

Here is my program in python and I am trying to save multiple plots in a single folder but it doesn't seem to work. How could I do this please?
for i in range(0:244):
plt.figure()
y = numpy.array(Data_EMG[i,:])
x = pylab.linspace(EMG_start, EMG_stop, Amount_samples)
plt.xlabel('Time(ms)')
plt.ylabel('EMG voltage(microV)')
pylab.plot(x, y)
pylab.show(block=True)
You can use the savefig function.
for i in range(0:244):
plt.figure()
y = numpy.array(Data_EMG[i,:])
x = pylab.linspace(EMG_start, EMG_stop, Amount_samples)
plt.xlabel('Time(ms)')
plt.ylabel('EMG voltage(microV)')
plt.savefig('EMG {0}.jpg'.format(i))
plt.close()
First of all check the identation. Hopefully your code actually reads
for i in range(0:244):
plt.figure()
y = numpy.array(Data_EMG[i,:])
x = pylab.linspace(EMG_start, EMG_stop, Amount_samples)
plt.xlabel('Time(ms)')
plt.ylabel('EMG voltage(microV)')
pylab.plot(x, y)
pylab.show(block=True)
At each iteration you completely generate a new figure. That´s very ineffective. Also you just plot your figure on the screen and not actually save it. Better is
from os import path
data = numpy.array(Data_EMG) # convert complete dataset into numpy-array
x = pylab.linspace(EMG_start, EMG_stop, Amount_samples) # doesn´t change in loop anyway
outpath = "path/of/your/folder/"
fig, ax = plt.subplots() # generate figure with axes
image, = ax.plot(x,data[0]) # initialize plot
ax.xlabel('Time(ms)')
ax.ylabel('EMG voltage(microV)')
plt.draw()
fig.savefig(path.join(outpath,"dataname_0.png")
for i in range(1, len(data)):
image.set_data(x,data[i])
plt.draw()
fig.savefig(path.join(outpath,"dataname_{0}.png".format(i))
Should be much faster.

Make plt.colorbar extend to the steps immediately before and after vmin/vmax

I want to do something with plt.hist2d and plt.colorbar and I'm having real trouble working out how to do it. To explain, I've written the following example:
import numpy as np
from matplotlib import pyplot as plt
x = np.random.random(1e6)
y = np.random.random(1e6)
plt.hist2d(x, y)
plt.colorbar()
plt.show()
This code generates a plot that looks something like the image below.
If I generate a histogram, ideally I would like the colour bar to extend beyond the maximum and minimum range of the data to the next step beyond the maximum and minimum. In the example in this question, this would set the colour bar extent from 9660 to 10260 in increments of 60.
How can I force either plt.hist2d or plt.colorbar to set the colour bar such that ticks are assigned to the start and end of the plotted colour bar?
I think this is what you're looking for:
h = plt.hist2d(x, y)
mn, mx = h[-1].get_clim()
mn = 60 * np.floor(mn / 60.)
mx = 60 * np.ceil(mx / 60.)
h[-1].set_clim(mn, mx)
cbar = plt.colorbar(h[-1], ticks=np.arange(mn, mx + 1, 60), )
This gives something like,
It's also often convenient to use tickers from the matplotlib.ticker, and use the tick_values method of tickers, but for this purpose I think the above is most convenient.
Good luck!
With huge thanks to farenorth, who got me thinking about this in the right way, I came up with a function, get_colour_bar_ticks:
def get_colour_bar_ticks(colourbar):
import numpy as np
# Get the limits and the extent of the colour bar.
limits = colourbar.get_clim()
extent = limits[1] - limits[0]
# Get the yticks of the colour bar as values (ax.get_yticks() returns them as fractions).
fractions = colourbar.ax.get_yticks()
yticks = (fractions * extent) + limits[0]
increment = yticks[1] - yticks[0]
# Generate the expanded ticks.
if (fractions[0] == 0) & (fractions[-1] == 1):
return yticks
else:
start = yticks[0] - increment
end = yticks[-1] + increment
if fractions[0] == 0:
newticks = np.concatenate((yticks, [end]))
elif fractions[1] == 1:
newticks = np.concatenate(([start], yticks))
else:
newticks = np.concatenate(([start], yticks, [end]))
return newticks
With this function I can then do this:
from matplotlib import pyplot as plt
x = np.random.random(1e6)
y = np.random.random(1e6)
h = plt.hist2d(x, y)
cbar = plt.colorbar()
ticks = get_colour_bar_ticks(cbar)
h[3].set_clim(ticks[0], ticks[-1])
cbar.set_clim(ticks[0], ticks[-1])
cbar.set_ticks(ticks)
plt.show()
Which results in this, which is what I really wanted:

increasing width of figure in matplotlib according to number of x values

I was trying to draw a barchart using matplotlib.The number of items to be plotted can vary . I cannot set the figure.set_size_inches(w,h) or set_figwidth(w) with constants(like 6.,8. or 8.,12. etc),since I cannot tell in advance what the value of w or h should be.I want the width of figure to increase as the number of items to be plotted increases.Can someone tell me how I can do this?
import pylab
def create_barchart(map):
xvaluenames = map.keys()
xvaluenames.sort()
yvalues = map.values()
max_yvalue = get_max_yvalue(yvalues)
xdata = range(len(xvaluenames))
ydata = [map[x] for x in xvaluenames]
splitxdata = [x.split('-',1) for x in xvaluenames]
xlabels = [x[0] for x in splitxdata]
figure = pylab.figure()
ax = figure.add_subplot(1,1,1)
figsize = figure.get_size_inches()
print 'figure size1=',figsize,'width=',figsize[0],'height=',figsize[1]
barwidth = .25
ystep = max_yvalue/5
pylab.grid(True)
if xdata and ydata:
ax.bar(xdata, ydata, width=barwidth,align='center',color='orange')
ax.set_xlabel('xvalues',color='green')
ax.set_ylabel('yvalues',color='green')
ax.set_xticks(xdata)
ax.set_xlim([min(xdata) - 0.5, max(xdata) + 0.5])
ax.set_xticklabels(xlabels)
ax.set_yticks(range(0,max_yvalue+ystep,ystep))
ax.set_ylim(0,max(ydata)+ystep)
figure.autofmt_xdate(rotation=30)
figure.savefig('mybarplot',format="png")
print 'figure size2=',figure.get_size_inches()
pylab.show()
def get_max_yvalue(yvals):
return max(yvals) if yvals else 0
if I try with a small set of items,I get
if __name__=='__main__':
datamap = dict(mark=39,jim=40, simon=20,dan=33)
print datamap
create_barchart(datamap)
but if I use a larger set
datamap = dict(mark=39,jim=40, simon=20,dan=33)
additional_values= dict(jon=34,ray=23,bert=45,kevin=35,ned=31,bran=11,tywin=56,tyrion=30,jaime=36,griffin=25,viserys=25)
datamap.update(additional_values)
create_barchart(datamap)
This looks awful,
I am wondering if there is a way to increase the width of figure,according to the number of items to be plotted,keeping the width of bars in both cases same
You can set the width when you initialize the figure:
# default scale is 1 in your original case, scales with other cases:
widthscale = len(yvalues)/4
figsize = (8*widthscale,6) # fig size in inches (width,height)
figure = pylab.figure(figsize = figsize) # set the figsize
Replace the figure = pylab.figure() line with the above three lines and you get what your asking for.

Categories

Resources