Matplotlib: strange minor ticks with log base 2 colorbar - matplotlib

I am plotting some contours with tricontourf. I want the colormap to be scaled in log values and tick labels and colours bounds to be in log base 2. Here's my code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import matplotlib.ticker as ticker
import matplotlib.colors as colors
section = 'T7'
data = np.loadtxt( section + '_values.dat')
x = data[:,0]
y = data[:,1]
z = data[:,2]
triang = tri.Triangulation(x,y)
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
bounds = [2.**-1,2.**1,2**3,2**5,2**7,2**9]
norm = colors.LogNorm()
formatter = ticker.LogFormatter(2)
tcf = ax1.tricontourf(triang, z, levels = bounds, cmap='hot_r', norm = norm )
fig1.colorbar(tcf, format=formatter)
plt.show()
And here's the result:
What are thos ugly minor ticks and how do I get rid of them?
Using Matplotlib 3.3.0 an Mac OS

You could use cb.ax.minorticks_off() to turn off the minor tick and cb.ax.minorticks_on() to turn it on.
cb = fig1.colorbar(tcf, format=formatter)
cb.ax.minorticks_off()
matplotlib.pyplot.colorbar returns a Colorbar object which extends ColorbarBase.
You can find that two functions in the document of class matplotlib.colorbar.ColorbarBase.

Related

imshow() extent limits not giving correct solution

I am a novice to python. I was trying to plot 2 D color plot using imshow(). Here, x axis is the time scale, yaxis is the energy and the colorbar z axis is the differential energy flux. When i plot somehow the y axis do not correspond to the actual value. I had tried using contourf as well as plotly heatmap. However I find though the results come correctly it does not have the same visual impact as imshow.
import matplotlib.pyplot as plt
from matplotlib import colors
import numpy as np
import matplotlib.dates as mdates
from mpl_toolkits.axes_grid1 import make_axes_locatable
import datetime as dt
x_lims = list(map(dt.datetime.utcfromtimestamp, [1266050102.1784432, 1266054264.5317998]))
x_lims = mdates.date2num(x_lims)
y1 = [3.1209615e+04, 2.6360914e+04, 2.0025836e+04, 1.5213330e+04, 1.1557158e+04,
8.7796689e+03, 6.6698813e+03, 5.0668237e+03, 3.8490525e+03, 2.9246511e+03,
2.2212300e+03, 1.6873538e+03, 1.2815887e+03, 9.7440747e+02, 7.3961621e+02,
5.6149872e+02, 4.2719626e+02, 3.2432623e+02, 2.4669749e+02, 1.8716624e+02,
1.4239874e+02, 1.0858500e+02, 8.2391251e+01, 6.2388748e+01, 4.7625000e+01,
3.6195000e+01, 2.7622499e+01, 2.0478750e+01, 1.5716249e+01, 1.2382500e+01,
9.0487499e+00, 7.1437497e+00]
y = np.array(y1)
y_lims = [y.min(), y.max()]
extent_lims = [x_lims[0], x_lims[1], y_lims[0], y_lims[1]]
z = flux_elec.T
fig, ax = plt.subplots()
im = ax.imshow(z, interpolation='none', extent=extent_lims, cmap='jet', aspect='auto')
date_format = mdates.DateFormatter('%H:%M')
ax.set_yscale('log')
ax.xaxis.set_major_formatter(date_format)
ax.xaxis_date()
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax, label="diff. en. flux")
[enter image description here](https://i.stack.imgur.com/Op1X7.png)
In this the high energy flux (8) should finish before 100 but its extending till 5000. I am unable to locate the error.

seaborn style whitegrid with no ticks

I want to create a scatter plot without x or y ticks. But I would like to see the plot in whitegrid style. When I explicitly sets the xticks, I lose the whitegrids too. Any tricks ?
import matplotlib.pyplot as plt
plt.style.use('ggplot')
import numpy as np
fig, ax = plt.subplots(frameon=False)
colormap = np.array(["orange","cyan"])
x = np.array([2,2,2,4,4,4,4]*10)
y = np.array([2,4])
col = np.array(['b','g'])
colors = colormap[np.where(y==x[:,None])[1]]
Y = np.random.random((70,2))
plt.xticks([])
plt.yticks([])
ax.scatter(Y[:,0], Y[:,1], c=colors)
You want to remove the tick labels, not the ticks themselves. Best to toggle their visibility attribute:
plt.setp(ax.get_xticklabels(), visible=False)
plt.setp(ax.get_yticklabels(), visible=False)
Below is the example you can refer as suggested by Mr T, you can make xticks font color to background color.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set_style("whitegrid")
fig, ax = plt.subplots(frameon=False)
colormap = np.array(["orange","cyan"])
x = np.array([2,2,2,4,4,4,4]*10)
y = np.array([2,4])
col = np.array(['b','g'])
colors = colormap[np.where(y==x[:,None])[1]]
Y = np.random.random((70,2))
ax.scatter(Y[:,0], Y[:,1], c=colors)
ax.tick_params(axis="both", colors="white") #suggested by Mr T, easier way
# plt.setp(ax.get_xticklabels(),color="white", backgroundcolor="white") # suggested by Me
# plt.setp(ax.get_yticklabels(),color="white", backgroundcolor="white") # suggested by Me
I have adopted Mr T's answer which is easier and less complicated.

How can one edit the "Text" object from the "Y" and "X" axis from a gridlined cartopy geopandas plot

This question arose from another Stackoverflow Issue 1:
My problem regards the edition of the X and Y axis ticklabels from a cartopy-geopandas plot. I would like to change my Text object from each of my ticklabels (X, and Y axis) according to a certain rule.
For example, I would like to change the decimal separator ('.') into comma separator (',') from my X and Y axis ticklabels.
Here is a code that can't do that:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import geopandas as gpd
Geopandas_DF = gpd.read_file('my_file.shp')
# setting projection and Transform
Projection=ccrs.PlateCarree()
Transform = ccrs.Geodetic(globe=ccrs.Globe(ellipse='GRS80'))
Fig, Ax = plt.subplots(1,1, subplot_kw={'projection': Projection})
Geopandas_DF.plot(ax=Ax, transform=Ax.transData)
gl = Ax.gridlines(crs=Projection , draw_labels=True, linewidth=0.5,
alpha=0.4, color='k', linestyle='--')
gl.top_labels = False
gl.right_labels = False
### Creating a function to change my Ticklabels:
def Ticker_corrector(ax):
"""
Parameter:ax, axes whose axis X and Y should be applied the function
"""
## Correcting the Axis X and Y of the main Axes
Xticks = ax.get_xticklabels()
for i in Xticks:
T = i.get_text()
T = T.replace('.',',')
i = i.set_text(T)
print(T)
ax.set_xticklabels(Xticks)
## Correcting the Axis Y
Yticks = ax.get_yticklabels()
for i in Xticks:
T = i.get_text()
T = T.replace('.',',')
i = i.set_text(T)
print(T)
ax.set_yticklabels(Yticks)
return ax
Ax = Ticker_corrector(Ax)
Fig.show()
One interesting part of the code above is that it runs without problem. The Python does not indicate any error in it, and it plots the Figure without any error warning.
Nonetheless, the Ticklabels are kept unchanged. Therefore, I need help with that problem.
I thank you for your time.
Sincerely yours,
I believe I have found a solution. It may not work always, but it certainly solved my problem.
The fundamental basis for the solution was to set the "Locale" of my matplotlib before creating my plot.
Here is an example:
import locale
locale.setlocale(locale.LC_ALL, "Portuguese_Brazil.1252")
import matplotlib as mpl
mpl.rcParams['axes.formatter.use_locale'] = True
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import geopandas as gpd
Geopandas_DF = gpd.read_file('my_file.shp')
# setting projection and Transform
Projection=ccrs.PlateCarree()
Transform = ccrs.Geodetic(globe=ccrs.Globe(ellipse='GRS80'))
Fig, Ax = plt.subplots(1,1, subplot_kw={'projection': Projection})
Geopandas_DF.plot(ax=Ax, transform=Ax.transData)
gl = Ax.gridlines(crs=Projection , draw_labels=True, linewidth=0.5,
alpha=0.4, color='k', linestyle='--')
gl.top_labels = False
gl.right_labels = False
Fig.show()

Adding Labels to a Shapefile Map

I have a shapefile that maps the world to sales territories. The shapefile records lists the sales territory code and name. I would like to be able to add the territory code in the center of the region, but to do using ax.text, I need the center point of the region. Any ideas how to do this?
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import shapefile
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex, Normalize
from matplotlib.patches import Polygon
from matplotlib.colorbar import ColorbarBase
from matplotlib.collections import PatchCollection
plt.rcParams['figure.figsize'] = [16,12]
fig = plt.figure()
m = Basemap(llcrnrlon=-121,llcrnrlat=20,urcrnrlon=-62,urcrnrlat=51,
projection='lcc',lat_1=32,lat_2=45,lon_0=-95)
shp_info = m.readshapefile('world_countries_boundary_file_world_2002','countries',drawbounds=True)
sf = shapefile.Reader('territory_map') # Custom file mapping out territories
recs = sf.records()
shapes = sf.shapes()
Nshp = len(shapes)
colors={}
territory_codes=[]
cmap = plt.cm.RdYlGn
# details is a pandas datafile with column "DELTA" that has data to plot
vmin = details.DELTA.min()
vmax = details.DELTA.max()
norm = Normalize(vmin=vmin, vmax=vmax)
for index,row in details.iterrows():
colors[row['TERRITORY_CODE']] = cmap((row['DELTA']-vmin)/(vmax-vmin))[:3]
territory_codes.append(row['TERRITORY_CODE'])
ax = fig.add_subplot(111)
for nshp in range(Nshp):
ptchs = []
pts = np.array((shapes[nshp].points))
prt = shapes[nshp].parts
par = list(prt) + [pts.shape[0]]
for pij in range(len(prt)):
ptchs.append(Polygon(pts[par[pij]:par[pij+1]]))
try:
color = rgb2hex(colors[recs[nshp][0]])
except:
color = 'w' # If no data, leave white (blank)
ax.add_collection(PatchCollection(ptchs, facecolor=color, edgecolor='b', linewidths=.7))
x, y = # Coordinates that are center of region
ax.text(x, y, recs[nshp][0]) # <---- this would be the text to add
# Add colorbar
ax_c = fig.add_axes([0.1, 0.1, 0.8, 0.02])
cb = ColorbarBase(ax_c,cmap=cmap,norm=norm,orientation='horizontal')
cb.ax.set_xlabel('Daily Change, USD')
#Set view to United States
ax.set_xlim(-150,-40)
ax.set_ylim(15,70)
plt.show()
Resulting Map of Code without Territory Names
you're probably looking to take the mean of all the x coordinates and the mean of all the y coordinates of your polygon shape.
I can't test this but it could look something like this:
x,y = pts[0].mean(), pts[1].mean()
or this:
x,y = pts[:,0].mean(), pts[:,1].mean()
depending on the dimensions of your numpy array.

Embedding small plots inside subplots in matplotlib

If you want to insert a small plot inside a bigger one you can use Axes, like here.
The problem is that I don't know how to do the same inside a subplot.
I have several subplots and I would like to plot a small plot inside each subplot.
The example code would be something like this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
for i in range(4):
ax = fig.add_subplot(2,2,i)
ax.plot(np.arange(11),np.arange(11),'b')
#b = ax.axes([0.7,0.7,0.2,0.2])
#it gives an error, AxesSubplot is not callable
#b = plt.axes([0.7,0.7,0.2,0.2])
#plt.plot(np.arange(3),np.arange(3)+11,'g')
#it plots the small plot in the selected position of the whole figure, not inside the subplot
Any ideas?
I wrote a function very similar to plt.axes. You could use it for plotting yours sub-subplots. There is an example...
import matplotlib.pyplot as plt
import numpy as np
#def add_subplot_axes(ax,rect,facecolor='w'): # matplotlib 2.0+
def add_subplot_axes(ax,rect,axisbg='w'):
fig = plt.gcf()
box = ax.get_position()
width = box.width
height = box.height
inax_position = ax.transAxes.transform(rect[0:2])
transFigure = fig.transFigure.inverted()
infig_position = transFigure.transform(inax_position)
x = infig_position[0]
y = infig_position[1]
width *= rect[2]
height *= rect[3] # <= Typo was here
#subax = fig.add_axes([x,y,width,height],facecolor=facecolor) # matplotlib 2.0+
subax = fig.add_axes([x,y,width,height],axisbg=axisbg)
x_labelsize = subax.get_xticklabels()[0].get_size()
y_labelsize = subax.get_yticklabels()[0].get_size()
x_labelsize *= rect[2]**0.5
y_labelsize *= rect[3]**0.5
subax.xaxis.set_tick_params(labelsize=x_labelsize)
subax.yaxis.set_tick_params(labelsize=y_labelsize)
return subax
def example1():
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
rect = [0.2,0.2,0.7,0.7]
ax1 = add_subplot_axes(ax,rect)
ax2 = add_subplot_axes(ax1,rect)
ax3 = add_subplot_axes(ax2,rect)
plt.show()
def example2():
fig = plt.figure(figsize=(10,10))
axes = []
subpos = [0.2,0.6,0.3,0.3]
x = np.linspace(-np.pi,np.pi)
for i in range(4):
axes.append(fig.add_subplot(2,2,i))
for axis in axes:
axis.set_xlim(-np.pi,np.pi)
axis.set_ylim(-1,3)
axis.plot(x,np.sin(x))
subax1 = add_subplot_axes(axis,subpos)
subax2 = add_subplot_axes(subax1,subpos)
subax1.plot(x,np.sin(x))
subax2.plot(x,np.sin(x))
if __name__ == '__main__':
example2()
plt.show()
You can now do this with matplotlibs inset_axes method (see docs):
from mpl_toolkits.axes_grid.inset_locator import inset_axes
inset_axes = inset_axes(parent_axes,
width="30%", # width = 30% of parent_bbox
height=1., # height : 1 inch
loc=3)
Update: As Kuti pointed out, for matplotlib version 2.1 or above, you should change the import statement to:
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
There is now also a full example showing all different options available.
From matplotlib 3.0 on, you can use matplotlib.axes.Axes.inset_axes:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2,2)
for ax in axes.flat:
ax.plot(np.arange(11),np.arange(11))
ins = ax.inset_axes([0.7,0.7,0.2,0.2])
plt.show()
The difference to mpl_toolkits.axes_grid.inset_locator.inset_axes mentionned in #jrieke's answer is that this is a lot easier to use (no extra imports etc.), but has the drawback of being slightly less flexible (no argument for padding or corner locations).
source: https://matplotlib.org/examples/pylab_examples/axes_demo.html
from mpl_toolkits.axes_grid.inset_locator import inset_axes
import matplotlib.pyplot as plt
import numpy as np
# create some data to use for the plot
dt = 0.001
t = np.arange(0.0, 10.0, dt)
r = np.exp(-t[:1000]/0.05) # impulse response
x = np.random.randn(len(t))
s = np.convolve(x, r)[:len(x)]*dt # colored noise
fig = plt.figure(figsize=(9, 4),facecolor='white')
ax = fig.add_subplot(121)
# the main axes is subplot(111) by default
plt.plot(t, s)
plt.axis([0, 1, 1.1*np.amin(s), 2*np.amax(s)])
plt.xlabel('time (s)')
plt.ylabel('current (nA)')
plt.title('Subplot 1: \n Gaussian colored noise')
# this is an inset axes over the main axes
inset_axes = inset_axes(ax,
width="50%", # width = 30% of parent_bbox
height=1.0, # height : 1 inch
loc=1)
n, bins, patches = plt.hist(s, 400, normed=1)
#plt.title('Probability')
plt.xticks([])
plt.yticks([])
ax = fig.add_subplot(122)
# the main axes is subplot(111) by default
plt.plot(t, s)
plt.axis([0, 1, 1.1*np.amin(s), 2*np.amax(s)])
plt.xlabel('time (s)')
plt.ylabel('current (nA)')
plt.title('Subplot 2: \n Gaussian colored noise')
plt.tight_layout()
plt.show()