Cleanest Way to Hide Every Nth Tick Label in Matplotlib Colorbar

Cleanest way to hide every nth tick label in matplotlib colorbar?

For loop the ticklabels, and call set_visible():

for label in cbar.ax.xaxis.get_ticklabels()[::2]:
label.set_visible(False)

Changing the tick frequency on the x or y axis

You could explicitly set where you want to tick marks with plt.xticks:

plt.xticks(np.arange(min(x), max(x)+1, 1.0))

For example,

import numpy as np
import matplotlib.pyplot as plt

x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.plot(x,y)
plt.xticks(np.arange(min(x), max(x)+1, 1.0))
plt.show()

(np.arange was used rather than Python's range function just in case min(x) and max(x) are floats instead of ints.)


The plt.plot (or ax.plot) function will automatically set default x and y limits. If you wish to keep those limits, and just change the stepsize of the tick marks, then you could use ax.get_xlim() to discover what limits Matplotlib has already set.

start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, stepsize))

The default tick formatter should do a decent job rounding the tick values to a sensible number of significant digits. However, if you wish to have more control over the format, you can define your own formatter. For example,

ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))

Here's a runnable example:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

x = [0,5,9,10,15]
y = [0,1,2,3,4]
fig, ax = plt.subplots()
ax.plot(x,y)
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, 0.712123))
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
plt.show()

Removing every 2nd xtick label only works for the first 6 ticks

As user @ImportanceOfBeingErnest suggested:

Solution 1:
Convert the x-axis data to numbers, so matplotbib takes care of the ticks automatically. In my case this is done by

pf.index = pf.index.map(int)

Solution 2:
Remove the ticks, after the graph is plotted, otherwise the objects don't exist yet and therefore can't be set invisible.
The new code would look like this:

data = pf.cum_perc
fig, ax = plt.subplots(figsize=(10, 6))
ax.set_xlabel("Days", size=18)
ax.set_ylabel("Share of reviews", size = 18)
ax.plot(data)

for label in ax.xaxis.get_ticklabels()[1::2]:
label.set_visible(False)

Make Matplotlib date xtick labels more sparse (spread out) by every nth xtick label

You can change the xticks to be every third day or what ever you input in [0::3]:

Import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
x = pd.date_range('2021-01-01', '2021-01-10')
y = np.random.randn(10)
plt.plot(x,y)
plt.xticks(x[0::3])
plt.show()

Sample Image

Now, per your comment, let's say you want to include the last value.

Import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

x = pd.date_range('2021-01-01', '2021-01-12')
y = np.random.randn(12)

plt.plot(x,y)
plt.xticks(x[0::3].append(x[-1:]))
plt.show()

Sample Image

Using locators without skipping tick labels

The pandas bar plot produces a plot where each bar is placed at a successive integer position, starting at 0. The locator in use is a FixedLocator, which stores those positions (0,1,2,3,...) and the formatter is a FixedFormatter that stores a ticklabel for each of those positions. If you now change the locator without changing the formatter things get out of sync. To avoid this, one needs to change both, the formatter and the locator. Since we do not have a good formatter to use in this case, we should rather stick to the FixedFormatter, which also implies to stick with the FixedLocator. We may still change the number of ticks for a FixedLocator and change the FixedFormatter to reflect this.

import matplotlib.pyplot as plt
from matplotlib import ticker
import pandas as pd

df = pd.DataFrame(columns=['bond 1','bond 2'],
index=[2017,2018,2019,2020,2021,2022])
df['bond 1'] = [4,5,6,6,5,4]
df['bond 2'] = [8,6,4,4,6,8]

fig,ax=plt.subplots(1)
ax = df.plot(ax=ax, kind='bar', colormap='copper')

locator = ax.xaxis.get_major_locator()
locator.locs = locator.locs[::2]
formatter = ax.xaxis.get_major_formatter()
formatter.seq = formatter.seq[::2]

plt.show()

matplotlib colorbar alternating top bottom labels

Jump to a simple working example:

import numpy
import matplotlib.pyplot as plt

#------------------Get some data------------------
X = numpy.arange(100)
Y = numpy.arange(100)
Z = numpy.arange(100**2).reshape((100,100))

levels=numpy.arange(0,100**2,1000)
ltop=levels[::2] # labels appear on top
lbot=levels[1:][::2] # labels appear at bottom

#-----------------------Plot-----------------------
f = plt.figure()
ax = f.gca()

cf = ax.contourf(X,Y,Z,100)
cbar=plt.colorbar(cf,orientation='horizontal',ticks=lbot,drawedges=True)

vmin=cbar.norm.vmin
vmax=cbar.norm.vmax

#-------------Print bottom tick labels-------------
cbar.ax.set_xticklabels(lbot)

#--------------Print top tick labels--------------
for ii in ltop:
cbar.ax.text((ii-vmin)/(vmax-vmin), 1.5, str(ii), transform=cbar.ax.transAxes, va='bottom', ha='center')

plt.show(block=False)

Basically the bottom labels are plotted using the default method cbar.ax.set_xticklabels(lbot). For the top labels, I added them manually using cbar.ax.text().

The plot looks like this:
colorbar with top and bottom labels

EDIT: IMPORTANT UPDATE TO MY ANSWER:

When the colorbar has extend/overflow, a triangle is used on the relevant end to indicate value overflow. In such cases the top line tick labels need some adjustment to properly align with colorbar sections.

By default the triangle size is 5% of the colorbar axis, this is used to get the proper offset and scaling to align the labels.

See an example below which has extends on both ends. Using my previous method, the result looks like this:

Sample Image

The 2 end numbers at top line are aligned with the tip of the triangles. If only one end has extend and the number of contour levels are big (>=10 or so), the misalignment will get worse.

The plot after correction:
Sample Image

And this is the code to generate the correct plot:

import numpy
import matplotlib.pyplot as plt

#------------------Get some data------------------
X = numpy.linspace(-1,1,100)
Y = numpy.linspace(-1,1,100)
X,Y=numpy.meshgrid(X,Y)
Z=numpy.sin(X**2)

levels=numpy.linspace(-0.8,0.8,9)

ltop=levels[::2] # labels appear on top
lbot=levels[1:][::2] # labels appear at bottom

#-----------------------Plot-----------------------
f = plt.figure()
ax = f.gca()

cf = ax.contourf(X,Y,Z,levels,extend='both')
cbar=plt.colorbar(cf,orientation='horizontal',ticks=lbot,drawedges=True)

#------------Compute top tick label locations------------
vmin=cbar.norm.vmin
vmax=cbar.norm.vmax

if cbar.extend=='min':
shift_l=0.05
scaling=0.95
elif cbar.extend=='max':
shift_l=0.
scaling=0.95
elif cbar.extend=='both':
shift_l=0.05
scaling=0.9
else:
shift_l=0.
scaling=1.0

#-------------Print bottom tick labels-------------
cbar.ax.set_xticklabels(lbot)

#--------------Print top tick labels--------------
for ii in ltop:
cbar.ax.text(shift_l + scaling*(ii-vmin)/(vmax-vmin),
1.5, str(ii), transform=cbar.ax.transAxes,
va='bottom', ha='center')

plt.show(block=False)

Pandas plot bar: Show every nth xlabel

If you are just trying to turn off the tick labels, you can do so by enumerating the .get_xticklabels() and turning off visibility for the ones you want to hide.

import pandas as pd
import numpy as np
x = np.linspace(100, 500, 51, dtype=int)

mydata = pd.DataFrame({'A': np.histogram(np.random.normal(300, 100, 500), bins=x)[0]},
index=x[:-1])

ax = mydata.plot.bar()

This is the graph produced
Sample Image

To change the x-axis labels, so only 1 in 5 show, use enumerate rather than the value of the label position to determine if it should be shown or not.

for i, t in enumerate(ax.get_xticklabels()):
if (i % 5) != 0:
t.set_visible(False)

Which produces this plot:
Sample Image

What could be causing this smearing/distortion on colorbar tick labels in these saved Matplotlib figures?

Clearing the figure at the end of the apply loop and setting the colorbar ticks with vmin and vmax solves the problem. See also this answer.

plt.matshow(..., vmin=0, vmax=1)

plt.clf()
plt.cla()
plt.close()


Related Topics



Leave a reply



Submit