Matplotlib: how to control the plot interval of x axis? - matplotlib

I'm plotting the degree of freedom against the square error,:
plt.plot([1,2,3,4], [0.5,0.6,0.9,0.85],'-')
It will produce
The problem is that ,the x ax is has 0.5 interval, and does not make sense in this context. Because there is simply no 1.5 degree of freedom.
How can I make the x axis into [1,2,3,4,], instead of [1, 1.5, 2, ...]?

Just add directly the positions and the strings you want to put in the x axis. Using your example:
import matplotlib.pyplot as plt
x = [1,2,3,4]
y = [0.5,0.6,0.9,0.85]
plt.plot(x,y,'-')
plt.xticks(list(range(1,max(x)+1)),[str(i) for i in range(1,max(x)+1)])
plt.grid()
plt.show()
, which results in:

You have to set the XTick 1 to 4, by 1 1:1:4 like below
plot([1,2,3,4], [0.5,0.6,0.9,0.85],'-');
set(gca,'XTick',1:1:4);
or
p = plot([1,2,3,4], [0.5,0.6,0.9,0.85],'-');
set(p,'XTick',1:1:4);

Related

Multiple different kinds of plots on a single figure and save it to a video

I am trying to plot multiple different plots on a single matplotlib figure with in a for loop. At the moment it is all good in matlab as shown in the picture below and then am able to save the figure as a video frame. Here is a link of a sample video generated in matlab for 10 frames
In python, tried it as below
import matplotlib.pyplot as plt
for frame in range(FrameStart,FrameEnd):#loop1
# data generation code within a for loop for n frames from source video
array1 = np.zeros((200, 3800))
array2 = np.zeros((19,2))
array3 = np.zeros((60,60))
for i in range(len(array2)):#loop2
#generate data for arrays 1 to 3 from the frame data
#end loop2
plt.subplot(6,1,1)
plt.imshow(DataArray,cmap='gray')
plt.subplot(6, 1, 2)
plt.bar(data2D[:,0], data2D[:,1])
plt.subplot(2, 2, 3)
plt.contourf(mapData)
# for fourth plot, use array2[3] and array2[5], plot it as shown and keep the\is #plot without erasing for next frame
not sure how to do the 4th axes with line plots. This needs to be there (done using hold on for this axis in matlab) for the entire sequence of frames processing in the for loop while the other 3 axes needs to be erased and updated with new data for each frame in the movie. The contour plot needs to be square all the time with color bar on the side. At the end of each frame processing, once all the axes are updated, it needs to be saved as a frame of a movie. Again this is easily done in matlab, but not sure in python.
Any suggestions
thanks
I guess you need something like this format.
I have used comments # in code to answer your queries. Please check the snippet
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(6,6))
ax1=fig.add_subplot(311) #3rows 1 column 1st plot
ax2=fig.add_subplot(312) #3rows 1 column 2nd plot
ax3=fig.add_subplot(325) #3rows 2 column 5th plot
ax4=fig.add_subplot(326) #3rows 2 column 6th plot
plt.show()
To turn off ticks you can use plt.axis('off'). I dont know how to interpolate your format so left it blank . You can adjust your figsize based on your requirements.
import numpy as np
from numpy import random
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(6,6)) #First is width Second is height
ax1=fig.add_subplot(311)
ax2=fig.add_subplot(312)
ax3=fig.add_subplot(325)
ax4=fig.add_subplot(326)
#Bar Plot
langs = ['C', 'C++', 'Java', 'Python', 'PHP']
students = [23,17,35,29,12]
ax2.bar(langs,students)
#Contour Plot
xlist = np.linspace(-3.0, 3.0, 100)
ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2)
cp = ax3.contourf(X, Y, Z)
fig.colorbar(cp,ax=ax3) #Add a colorbar to a plot
#Multiple line plot
x = np.linspace(-1, 1, 50)
y1 = 2*x + 1
y2 = 2**x + 1
ax4.plot(x, y2)
ax4.plot(x, y1, color='red',linewidth=1.0)
plt.tight_layout() #Make sures plots dont overlap
plt.show()

Creating a grid of polar histograms (python)

I wish to create a sub plot that looks like the following picture,
it is supposed to contain 25 polar histograms, and I wish to add them to the plot one by one.
needs to be in python.
I already figured I need to use matplotlib but can't seem to figure it out completely.
thanks a lot!
You can create a grid of polar axes via projection='polar'.
hist creates a histogram, also when working with polar axes. Note that the x is in radians with a range of 2π. It works best when you give the bins explicitly as a linspace from 0 to 2π (or from -π to π, depending on the data). The third parameter of linspace should be one more than the number of bars that you'd want for the full circle.
About the exact parameters of axs[i][j].hist(x, bins=np.linspace(0, 2 * np.pi, np.random.randint(7, 30), endpoint=True), color='dodgerblue', ec='black'):
axs[i][j] draw on the jth subplot of the ith line
.hist create a histogram
x: the values that are put into bins
bins=: to enter the bins (either a fixed number between lowest and highest x or some explicit boundaries; default is 10 fixed boundaries)
np.random.randint(7, 30) a random whole number between 7 and 29
np.linspace(0, 2 * np.pi, n, endpoint=True) divide the range between 0 and 2π into n equal parts; endpoint=True makes boundaries at 0, at 2π and at n-2 positions in between; when endpoint=False there will be a boundary at 0, at n-1 positions in between but none at the end
color='dodgerblue': the color of the histogram bars will be blueish
ec='black': the edge color of the bars will be black
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(5, 5, figsize=(8, 8),
subplot_kw=dict(projection='polar'))
for i in range(5):
for j in range(5):
x = np.random.uniform(0, 2 * np.pi, 50)
axs[i][j].hist(x, bins=np.linspace(0, 2 * np.pi, np.random.randint(7, 30)), color='dodgerblue', ec='black')
plt.tight_layout()
plt.show()

How can I use matplotlib ticklabel_format to not use scientific notation on y axis labels

I'm creating a plot (in a colab worksheet) and want the y tick labels to not use scientific notation. The ticklabel_format doesn't make any difference to the final graph. The y axis labels are still shown as 10^3 instead of 1000. How do I format the y tick labels to not use scientific notation?
Here is my code
import matplotlib.pyplot as plt
plt.ticklabel_format(style='plain', axis='y')
plt.plot(Cd_rank,Cd_raw,linewidth=4)
plt.plot(Cd_rank,Cd_sed,linewidth=4)
plt.plot(Cd_rank,Cd_filter,linewidth=4)
plt.plot([0,1],[0.3,0.3],linewidth=4)
plt.plot([0,1],[5,5],linewidth=4)
plt.ylabel('Turbidez (UTN)')
plt.xlabel('Datos ordenados')
plt.yscale('log')
plt.legend(['Agua cruda','Decantada','Filtrada','Norma EPA','Norma ENACAL'])
The ScalarFormatter shows the tick labels in a default format. Note that depending on your concrete situation, matplotlib still might be using scientific notation:
When the numbers are too high (default this is about 4 digits). set_powerlimits((n, m)) can be used to change the limits.
In case the numbers are very close together, matplotlib describes the range using an offset. That offset is placed at the top of the axis. This can be suppressed with the useOffset=None parameter of the formatter.
In some cases with a logarithmic scale, there are very few major ticks. Then also some (but not all) minor ticks get a label. Also for these, the formatter could be changed. A problem can be that a simple ScalarFormatter will set too many labels. Either suppress all these minor labels using a NullFormatter or you'll need a very custom formatter that returns empty strings for the minor tick labels that need to be suppressed.
A simple example:
from matplotlib import pyplot as plt
from matplotlib import ticker
import numpy as np
N = 50
Cd_rank = np.linspace(0, 100, N)
Cd_raw = np.random.normal(1, 20, N).cumsum() + 100
plt.plot(Cd_rank, Cd_raw, linewidth=4)
plt.plot([0, 1], [0.3, 0.3], linewidth=4)
plt.plot([0, 1], [5, 5], linewidth=4)
plt.yscale('log')
plt.gca().yaxis.set_major_formatter(ticker.ScalarFormatter())
plt.gca().yaxis.set_minor_formatter(ticker.NullFormatter())
plt.show()
And here is a more complicated example, with both minor (green) and major (red) ticks.
from matplotlib import pyplot as plt
from matplotlib import ticker
import numpy as np
N = 50
Cd_rank = np.linspace(0, 100, N)
Cd_raw = np.random.normal(10, 5, N).cumsum() + 80
plt.plot(Cd_rank, Cd_raw, linewidth=4)
plt.yscale('log')
mticker = ticker.ScalarFormatter(useOffset=False)
mticker.set_powerlimits((-6, 6))
ax = plt.gca()
ax.yaxis.set_major_formatter(mticker)
ax.yaxis.set_minor_formatter(mticker)
ax.tick_params(axis='y', which='major', colors='crimson')
ax.tick_params(axis='y', which='minor', colors='seagreen')
plt.show()
PS: When the ticks involve both powers of 10 larger than 1 and smaller than 1 (so, e.g. 100, 10, 1, 0.1, 0.01) the ScalarFormatter doesn't display the numbers smaller than 1 well (it displays 0.1 and 0.01 as 0). In that case, the StrMethodFormatter can be used instead:
plt.gca().yaxis.set_major_formatter(ticker.StrMethodFormatter("{x}"))
Here is code that turns off scientific notation and handles numbers that are smaller than 1 correctly. Thanks to #Johanc for this code.
from matplotlib import pyplot as plt
from matplotlib import ticker
import numpy as np
N = 50
x = np.linspace(0,1,N)
y = np.logspace(-3, 2, N)
plt.plot(x, y, linewidth=4)
plt.yscale('log')
plt.ylim(bottom=0.001,top=100)
plt.gca().yaxis.set_major_formatter(ticker.ScalarFormatter())
plt.gca().yaxis.set_major_formatter(ticker.StrMethodFormatter("{x}"))
plt.show()```

plot ordering/layering julia pyplot

I have a subplot that plots a line (x,y) and a particular point (xx,yy). I want to highligh (xx,yy), so I've plotted it with scatter. However, even if I order it after the original plot, the new point still shows up behind the original line. How can I fix this? MWE below.
x = 1:10
y = 1:10
xx = 5
yy = 5
fig, ax = subplots()
ax[:plot](x,y)
ax[:scatter](xx,yy, color="red", label="h_star", s=100)
legend()
xlabel("x")
ylabel("y")
title("test")
grid("on")
You can change which plots are displayed on top of each other with the argument zorder. The matplotlib example shown here gives a brief explanation:
The default drawing order for axes is patches, lines, text. This
order is determined by the zorder attribute. The following defaults
are set
Artist Z-order
Patch / PatchCollection 1
Line2D / LineCollection 2
Text 3
You can change the order for individual artists by setting the zorder.
Any individual plot() call can set a value for the zorder of that
particular item.
A full example based on the code in the question, using python is shown below:
import matplotlib.pyplot as plt
x = range(1,10)
y = range(1,10)
xx = 5
yy = 5
fig, ax = plt.subplots()
ax.plot(x,y)
# could set zorder very high, say 10, to "make sure" it will be on the top
ax.scatter(xx,yy, color="red", label="h_star", s=100, zorder=3)
plt.legend()
plt.xlabel("x")
plt.ylabel("y")
plt.title("test")
plt.grid("on")
plt.show()
Which gives:

Mutiple plots in a single window

I need to draw many such rows (for a0 .. a128) in a single window. I've searched in FacetGrid, PairGrid and all over around but couldn't find. Only regplot has similar argument ax but it doesn't plot histograms. My data is 128 real valued features with label column [0, 1]. I need the graphs to be shown from my Python code as a separate application on Linux.
Also, it there a way to scale this histogram to show relative values on Y such that the right curve is not skewed?
g = sns.FacetGrid(df, col="Result")
g.map(plt.hist, "a0", bins=20)
plt.show()
Just a simple example using matplotlib. The code is not optimized (ugly, but simple plot-indexing):
import numpy as np
import matplotlib.pyplot as plt
N = 5
data = np.random.normal(size=(N*N, 1000))
f, axarr = plt.subplots(N, N) # maybe you want sharex=True, sharey=True
pi = [0,0]
for i in range(data.shape[0]):
if pi[1] == N:
pi[0] += 1 # next row
pi[1] = 0 # first column again
axarr[pi[0], pi[1]].hist(data[i], normed=True) # i was wrong with density;
# normed=True should be used
pi[1] += 1
plt.show()
Output: