Modifying the Grid in matplotlib.pyplot graph - python

I am a newbie to Python but slowly getting there. I am having a problem trying to increase the number of grid lines on a graph. Basically, the Graph is labelled 0-24 (Hours) but the x axis only generates a label every 5 hours (O,5,10,15,20) with a grid line at each of those majors. Ideally, I would like a grid line every hour as I am collecting real time data.
Most of this code has been lifted from various sources, but the one thing that has stumped me is how to configure the grid..
Edit - As requested my simplified code is below..
import numpy as np
import matplotlib.pyplot as plt
import time
timedata=[0.01,1.1,2.2,3.3,4.4,5.55,6.6,7.7,8.8,9.1,10.2,11.2,12.2,13.2,14.1,15.2,16.1,17.2,18.1,19.2,20.1,21.1,22.2,23.1]
#timedata is in decimal hours
bxdata=[10,10,20,20,20,30,30,30,40,40,40,30,30,30,20,20,30,30,20,20,40,50,30,24]
bydata=[20,10,20,30,20,30,30,30,5,40,40,30,5,30,20,20,30,35,20,20,5,50,30,24]
#draw the graph
fig, ax = plt.subplots(sharex=True, figsize=(12, 6))
x=np.arange(0,24,1)
ax.plot(timedata,bxdata, color='red', label='Bx',lw=1)
ax.plot (timedata, bydata, color='blue', label = 'By',lw=1)
ax.set_xlim(0,24)
ax.set_ylim(-250,250)
plt.ion()
plt.xlabel("Time (Hours)")
plt.ylabel("nT")
plt.grid(True, which='both')
plt.legend()
plt.show()
image = "test.png"
time.sleep(2)
plt.savefig(image)
plt.close('all')
and this is the graph that I get.

The idea is to associate a locator to the minor x-axis ticks, the locator you need is MultipleLocator and we use it also to fix the major ticks' spacing (for hours, 6 is better than 5, isn't it?)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
y = np.random.rand(25)
plt.plot(y)
plt.gca().xaxis.set_major_locator(MultipleLocator(6))
plt.gca().xaxis.set_minor_locator(MultipleLocator(1))
plt.grid()
plt.grid(True, 'minor', color='#ddddee') # use a lighter color
plt.show()

If you set the x-axis spacing to any desired interval, the grid will automatically be drawn in conjunction with it. There is a mixture of object-oriented and plot formats, so the object format is used for unification.
import numpy as np
import matplotlib.pyplot as plt
import time
timedata=[0.01,1.1,2.2,3.3,4.4,5.55,6.6,7.7,8.8,9.1,10.2,11.2,12.2,13.2,14.1,15.2,16.1,17.2,18.1,19.2,20.1,21.1,22.2,23.1]
#timedata is in decimal hours
bxdata=[10,10,20,20,20,30,30,30,40,40,40,30,30,30,20,20,30,30,20,20,40,50,30,24]
bydata=[20,10,20,30,20,30,30,30,5,40,40,30,5,30,20,20,30,35,20,20,5,50,30,24]
#draw the graph
fig, ax = plt.subplots(sharex=True, figsize=(12, 6))
x=np.arange(0,24,1)
ax.plot(timedata,bxdata, color='red', label='Bx',lw=1)
ax.plot(timedata, bydata, color='blue', label='By',lw=1)
ax.set_xlim(0,24)
ax.set_ylim(-250,250)
# plt.ion()
ax.set_xticks(np.arange(0,24,1))
ax.set_xlabel("Time (Hours)")
ax.set_ylabel("nT")
ax.grid(True, which='both')
ax.legend()
# image = "test.png"
# time.sleep(2)
# plt.savefig(image)
# plt.close('all')
plt.show()

Related

Seaborn Adjusting Markers

As you can see here, the X axis labels here are quite unreadable. This will happen regardless of how I adjust the figure size. I'm trying to figure out how to adjust the labeling so that it only shows certain points. The X axis are all numerical between -1 to 1, and I think it would be nice and more viewer friendly to have labels at -1, -.5, 0, .5 and 1.
Is there a way to do this? Thank you!
Here's my code
sns.set(rc={'figure.figsize':(20,8)})
ax = sns.countplot(musi['Positivity'])
ax.set_xticklabels(ax.get_xticklabels(), rotation=40, ha='right')
plt.tight_layout()
plt.show()
Basically seaborn is wrapper on matplotlib. You can use matplotlib ticker function to do a Job. Refer the below example.
Let's Plots tick every 1 spacing.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns
sns.set_theme(style="whitegrid")
x = [0,5,9,10,15]
y = [0,1,2,3,4]
tick_spacing = 1
fig, ax = plt.subplots(1,1)
sns.lineplot(x, y)
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()
Now Let's plot ticks every 5 ticks.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns
sns.set_theme(style="whitegrid")
x = [0,5,9,10,15]
y = [0,1,2,3,4]
tick_spacing = 5
fig, ax = plt.subplots(1,1)
sns.lineplot(x, y)
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()
P.S.: This solution give you explicit control of the tick spacing via the number given to ticker.MultipleLocater(), allows automatic limit determination, and is easy to read later.

Colorbar at the top of a figure: matplotlib [duplicate]

I have a matplotlib plot with a colorbar attached. I want to position the colorbar so that it is horizontal, and underneath my plot.
I have almost done this via the following:
plt.colorbar(orientation="horizontal",fraction=0.07,anchor=(1.0,0.0))
But the colorbar is still overlapping with the plot slightly (and the labels of the x axis). I want to move the colorbar further down, but I can't figure out how to do it.
using padding pad
In order to move the colorbar relative to the subplot, one may use the pad argument to fig.colorbar.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")
fig.colorbar(im, orientation="horizontal", pad=0.2)
plt.show()
using an axes divider
One can use an instance of make_axes_locatable to divide the axes and create a new axes which is perfectly aligned to the image plot. Again, the pad argument would allow to set the space between the two axes.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np; np.random.seed(1)
fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")
divider = make_axes_locatable(ax)
cax = divider.new_vertical(size="5%", pad=0.7, pack_start=True)
fig.add_axes(cax)
fig.colorbar(im, cax=cax, orientation="horizontal")
plt.show()
using subplots
One can directly create two rows of subplots, one for the image and one for the colorbar. Then, setting the height_ratios as gridspec_kw={"height_ratios":[1, 0.05]} in the figure creation, makes one of the subplots much smaller in height than the other and this small subplot can host the colorbar.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
fig, (ax, cax) = plt.subplots(nrows=2,figsize=(4,4),
gridspec_kw={"height_ratios":[1, 0.05]})
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")
fig.colorbar(im, cax=cax, orientation="horizontal")
plt.show()
Edit: Updated for matplotlib version >= 3.
Three great ways to do this have already been shared in this answer.
The matplotlib documentation advises to use inset_locator. This would work as follows:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np
rng = np.random.default_rng(1)
fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(rng.random((11, 16)))
ax.set_xlabel("x label")
axins = inset_axes(ax,
width="100%",
height="5%",
loc='lower center',
borderpad=-5
)
fig.colorbar(im, cax=axins, orientation="horizontal")

How to change the frequency of labeling the x and y axis in matplotlib in python?

I am trying to plot a circle with a grid being shown. I wrote the following script which gives the below picture. However, the labels on the axes are interfering together. How to make the label appear (..,-10,-5,0,5,10,...) KEEPING the grid as it appears in the below figure?. I want to keep the dimension of the grid cell as 1*1 dimension.
I tried to use plt.locator_params(), but the dimension of the grid cell changed and became bigger.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib.pyplot import figure
R1=28
n=64
t=np.linspace(0, 2*np.pi, n)
x1=R1*np.cos(t)
y1=R1*np.sin(t)
plt.axis("square")
plt.grid(True, which='both', axis='both')
plt.xticks(np.arange(min(x1)-2,max(x1)+2, step=1))
plt.yticks(np.arange(min(y1)-2,max(y1)+2, step=1))
#plt.locator_params(axis='x', nbins=5)
#plt.locator_params(axis='y', nbins=5)
plt.plot(x1,y1)
plt.legend()
plt.show()
Not a matplotlib expert, so there may be a better way to do this, but perhaps like the following:
from matplotlib.ticker import MultipleLocator
...
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(x1,y1)
ax.xaxis.set_minor_locator(MultipleLocator())
ax.xaxis.set_major_locator(MultipleLocator(5))
ax.yaxis.set_minor_locator(MultipleLocator())
ax.yaxis.set_major_locator(MultipleLocator(5))
ax.grid(True, which='both', axis='both')
plt.show()

force matplotlib to fix the plot area

I have multiple plots that have the same x-axis. I would like to stack them in a report and have everything line up. However, matplotlib seems to resize them slightly based on the y tick label length.
Is it possible to force the plot area and location to remain the same across plots, relative to the pdf canvas to which I save it?
import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0.,2.,0.00001)
ys1=np.sin(xs*10.) #makes the long yticklabels
ys2=10.*np.sin(xs*10.)+10. #makes the short yticklabels
fig=plt.figure() #this plot ends up shifted right on the canvas
plt.plot(xs,ys1,linewidth=2.0)
plt.xlabel('x')
plt.ylabel('y')
fig=plt.figure() #this plot ends up further left on the canvas
plt.plot(xs,ys2,linewidth=2.0)
plt.xlabel('x')
plt.ylabel('y')
Your problem is a little unclear, however plotting them as subplots in the same figure should gaurantee that the axes and figure size of the two subplots will be alligned with each other
import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0.,2.,0.00001)
ys1=np.sin(xs*10.) #makes the long yticklabels
ys2=10.*np.sin(xs*10.)+10. #makes the short yticklabels
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.plot(xs,ys1,linewidth=2.0)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax2.plot(xs,ys2,linewidth=2.0)
ax2.set_xlabel('x')
ax2.set_ylabel('y')
plt.subplots_adjust(hspace=0.3) # adjust spacing between plots
plt.show()
This produces the following figure:
I had the same problem. The following works for me.
Force the same figure width for all your plots around all your python scripts, for example:
fig1 = plt.figure(figsize=(12,6))
...
fig2 = plt.figure(figsize=(12,4))
And do not use (very important!):
fig.tight_layout()
Save the figure
plt.savefig('figure.png')
Plot areas should now be the same.
using subplots with the same x-axis should do the trick.
use sharex=True when you create the subplots. The benefit of sharex is that zooming or panning on 1 subplot will also auto-update on all subplots with shared axes.
import numpy as np
import matplotlib.pyplot as plt
xs = np.arange(0., 2., 0.00001)
ys1 = np.sin(xs * 10.) # makes the long yticklabels
ys2 = 10. * np.sin(xs * 10.) + 10. # makes the short yticklabels
fig, (ax1, ax2) = plt.subplots(2, sharex=True)
ax1.plot(xs, ys1, linewidth=2.0)
ax1.xlabel('x')
ax1.ylabel('y')
ax2.plot(xs, ys2, linewidth=2.0)
ax2.xlabel('x')
ax2.ylabel('y')
plt.show()

Matplotlib Enlarge the space between x-axis labels

I want to increase the space between the labels in the x-axis so that they wont stay side by side.
Is there anyway I could "drag" the plot horizontally, its like what I could do in the excel when I drag the plot horizontally to the right, the entire plot gets larger.
Here is the current screenshot:
I did use code like ax.xaxis.get_children()1.set_size(100), but its not working.
import matplotlib.pyplot as plt
import numpy as np
line = plt.figure()
plt.plot(x,y, 'r-',marker='o', color='b')
plt.grid(True)
plt.xticks(x, Quickdatres,rotation="vertical")
ax=plt.subplot()
ax.xaxis.get_children()[1].set_size(100)
for label in ax.xaxis.get_ticklabels()[::2]:
label.set_visible(False)
plt.show()
Quickdatres contains all labels for x-axis. Thx!
You could increase the interval between labels from 3 to 5. (I had to construct fake data to be able to plot).
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(402, 630)
Quickdatres = [str(_) if _%5==0 else '' for _ in x]
y = np.random.randint(500, 3000, 630-402)
line = plt.figure()
plt.plot(x, y, 'r-', marker='o', color='b')
plt.grid(True)
plt.xticks(x, Quickdatres, rotation="vertical")
ax = plt.subplot()
ax.xaxis.get_children()[1].set_size(100)
for label in ax.xaxis.get_ticklabels()[::2]:
label.set_visible(False)
plt.show()

Categories

Resources