Hide the short lines of axis tickers in plt.subplots [duplicate] - python

I can remove the ticks with
ax.set_xticks([])
ax.set_yticks([])
but this removes the labels as well. Any way I can plot the tick labels but not the ticks and the spine

You can set the tick length to 0 using tick_params (http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.tick_params):
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1],[1])
ax.tick_params(axis=u'both', which=u'both',length=0)
plt.show()

Thanks for your answers #julien-spronck and #cmidi.
As a note, I had to use both methods to make it work:
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(11, 3))
data = np.random.random((4, 4))
ax1.imshow(data)
ax1.set(title='Bad', ylabel='$A_y$')
# plt.setp(ax1.get_xticklabels(), visible=False)
# plt.setp(ax1.get_yticklabels(), visible=False)
ax1.tick_params(axis='both', which='both', length=0)
ax2.imshow(data)
ax2.set(title='Somewhat OK', ylabel='$B_y$')
plt.setp(ax2.get_xticklabels(), visible=False)
plt.setp(ax2.get_yticklabels(), visible=False)
# ax2.tick_params(axis='both', which='both', length=0)
ax3.imshow(data)
ax3.set(title='Nice', ylabel='$C_y$')
plt.setp(ax3.get_xticklabels(), visible=False)
plt.setp(ax3.get_yticklabels(), visible=False)
ax3.tick_params(axis='both', which='both', length=0)
plt.show()

While attending a coursera course on Python, this was a question.
Below is the given solution, which I think is more readable and intuitive.
ax.tick_params(top=False,
bottom=False,
left=False,
right=False,
labelleft=True,
labelbottom=True)

This worked for me:
plt.tick_params(axis='both', labelsize=0, length = 0)

matplotlib.pyplot.setp(*args, **kwargs) is used to set properties of an artist object. You can use this in addition to get_xticklabels() to make it invisible.
something on the lines of the following
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(2,1,1)
ax.set_xlabel("X-Label",fontsize=10,color='red')
plt.setp(ax.get_xticklabels(),visible=False)
Below is the reference page
http://matplotlib.org/api/pyplot_api.html

You can set the yaxis and xaxis set_ticks_position properties so they just show on the left and bottom sides, respectively.
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
Furthermore, you can hide the spines as well by setting the set_visible property of the specific spine to False.
axes[i].spines['right'].set_visible(False)
axes[i].spines['top'].set_visible(False)

This Worked out pretty well for me! try it out
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
languages =['Python', 'SQL', 'Java', 'C++', 'JavaScript']
pos = np.arange(len(languages))
popularity = [56, 39, 34, 34, 29]
plt.bar(pos, popularity, align='center')
plt.xticks(pos, languages)
plt.ylabel('% Popularity')
plt.title('Top 5 Languages for Math & Data \nby % popularity on Stack Overflow',
alpha=0.8)
# remove all the ticks (both axes),
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off',
labelbottom='on')
plt.show()

Currently came across the same issue, solved as follows on version 3.3.3:
# My matplotlib ver: 3.3.3
ax.tick_params(tick1On=False) # "for left and bottom ticks"
ax.tick_params(tick2On=False) # "for right and top ticks, which are off by default"
Example:
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
ax.tick_params(tick1On=False)
plt.show()
Output:

Assuming that you want to remove some ticks on the Y axes and only show the yticks that correspond to the ticks that have values higher than 0 you can do the following:
from import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# yticks and yticks labels
yTicks = list(range(26))
yTicks = [yTick if yTick % 5 == 0 else 0 for yTick in yTicks]
yTickLabels = [str(yTick) if yTick % 5 == 0 else '' for yTick in yTicks]
Then you set up your axis object's Y axes as follow:
ax.yaxis.grid(True)
ax.set_yticks(yTicks)
ax.set_yticklabels(yTickLabels, fontsize=6)
fig.savefig('temp.png')
plt.close()
And you'll get a plot like this:

Related

Set the number of minor ticks in matplotlib colorbar

I am able to set the number of major ticks of the colorbar using the following code borrowed from here:
cbar = plt.colorbar()
cbar.ax.locator_params(nbins=5)
Is there a similar way of setting the minor ticks of the colorbar?
You can use the AutoMinorLocator to set the number of minor ticks (note that when setting n=4, one of the major ticks is counted as 1). Here is an example:
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator, ScalarFormatter
import numpy as np
data = np.random.rand(10, 10)
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 5))
img1 = ax1.imshow(data, cmap='inferno', aspect='auto', vmin=0, vmax=1)
cbar1 = plt.colorbar(img1, ax=ax1)
ax1.set_title('default colorbar ticks')
img2 = ax2.imshow(data, cmap='inferno', aspect='auto', vmin=0, vmax=1)
cbar2 = plt.colorbar(img2, ax=ax2)
# 3 major ticks
cbar2.ax.locator_params(nbins=3)
# 4 minor ticks, including one major, so 3 minor ticks visible
cbar2.ax.yaxis.set_minor_locator(AutoMinorLocator(n=4))
# show minor tick labels
cbar2.ax.yaxis.set_minor_formatter(ScalarFormatter())
# change the color to better distinguish them
cbar2.ax.tick_params(which='minor', color='blue', labelcolor='crimson')
ax2.set_title('3 major, 4 minor colorbar ticks')
plt.tight_layout()
plt.show()

How to plot a paired histogram using seaborn

I would like to make a paired histogram like the one shown here using the seaborn distplot.
This kind of plot can also be referred to as the back-to-back histogram shown here, or a bihistogram inverted/mirrored along the x-axis as discussed here.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
green = np.random.normal(20,10,1000)
blue = np.random.poisson(60,1000)
fig, ax = plt.subplots(figsize=(8,6))
sns.distplot(blue, hist=True, kde=True, hist_kws={'edgecolor':'black'}, kde_kws={'linewidth':2}, bins=10, color='blue')
sns.distplot(green, hist=True, kde=True, hist_kws={'edgecolor':'black'}, kde_kws={'linewidth':2}, bins=10, color='green')
ax.set_xticks(np.arange(-20,121,20))
ax.set_yticks(np.arange(0.0,0.07,0.01))
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
Here is the output:
When I use the method discussed here (plt.barh), I get the bar plot shown just below, which is not what I am looking for.
Or maybe I haven't understood the workaround well enough...
A simple/short implementation of python-seaborn-distplot similar to these kinds of plots would be perfect. I edited the figure of my first plot above to show the kind of plot I hope to achieve (though y-axis not upside down):
Any leads would be greatly appreciated.
You could use two subplots and invert the y-axis of the lower one and plot with the same bins.
df = pd.DataFrame({'a': np.random.normal(0,5,1000), 'b': np.random.normal(20,5,1000)})
fig =plt.figure(figsize=(5,5))
ax = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
bins = np.arange(-20,40)
ax.hist(df['a'], bins=bins)
ax2.hist(df['b'],color='orange', bins=bins)
ax2.invert_yaxis()
edit:
improvements suggested by #mwaskom
fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True, figsize=(5,5))
bins = np.arange(-20,40)
for ax, column, color, invert in zip(axes.ravel(), df.columns, ['teal', 'orange'], [False,True]):
ax.hist(df[column], bins=bins, color=color)
if invert:
ax.invert_yaxis()
plt.subplots_adjust(hspace=0)
Here is a possible approach using seaborn's displots.
Seaborn doesn't return the created graphical elements, but the ax can be interrogated. To make sure the ax only contains the elements you want upside down, those elements can be drawn first. Then, all the patches (the rectangular bars) and the lines (the curve for the kde) can be given their height in negative. Optionally the x-axis can be set at y == 0 using ax.spines['bottom'].set_position('zero').
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
green = np.random.normal(20, 10, 1000)
blue = np.random.poisson(60, 1000)
fig, ax = plt.subplots(figsize=(8, 6))
sns.distplot(green, hist=True, kde=True, hist_kws={'edgecolor': 'black'}, kde_kws={'linewidth': 2}, bins=10,
color='green')
for p in ax.patches: # turn the histogram upside down
p.set_height(-p.get_height())
for l in ax.lines: # turn the kde curve upside down
l.set_ydata(-l.get_ydata())
sns.distplot(blue, hist=True, kde=True, hist_kws={'edgecolor': 'black'}, kde_kws={'linewidth': 2}, bins=10,
color='blue')
ax.set_xticks(np.arange(-20, 121, 20))
ax.set_yticks(np.arange(0.0, 0.07, 0.01))
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
pos_ticks = np.array([t for t in ax.get_yticks() if t > 0])
ticks = np.concatenate([-pos_ticks[::-1], [0], pos_ticks])
ax.set_yticks(ticks)
ax.set_yticklabels([f'{abs(t):.2f}' for t in ticks])
ax.spines['bottom'].set_position('zero')
plt.show()

Show axis at center, but keep labels on the left [duplicate]

This question already has answers here:
How to move tick labels off left spine
(2 answers)
Closed 3 years ago.
I am attempting to plot a distribution which is centred around zero, and as such I want to show the y-axis spine at 0, but I want to keep the tick labels themselves to the left of the graph (i.e. outside the plot area). I thought this might be achievable through tick_params, but the labelleft option seems to keep the labels in the centre. A short example is as follows:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
vals = np.random.normal(loc=0, scale=10, size=300)
bins = range(int(min(vals)), int(max(vals))+1)
fig, ax = plt.subplots(figsize=(15,5))
ax.hist(vals, bins=bins)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.grid(axis='y', which='major', alpha=0.5)
plt.show()
This gives you:
I would like the labels to be at the left end of the gridlines, rather than the centre of the plot.
Probably not the best solution, but you can set left spines invisible and draw a straight line at 0:
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.plot((0,0), (0,ax.get_ylim()[-1]),color='k',linewidth=1)
ax.grid(axis='y', which='major', alpha=0.5)
plt.show()
Output:
On possibility is to instruct the tick labels to use the "Axes coordinates" for their x position, and the "Data coordinates" for their y position. This implies changing their tranform property.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.transforms as transforms
np.random.seed(1)
vals = np.random.normal(loc=0, scale=10, size=300)
bins = range(int(min(vals)), int(max(vals))+1)
fig, ax = plt.subplots()
ax.hist(vals, bins=bins)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.grid(axis='y', which='major', alpha=0.5)
trans = transforms.blended_transform_factory(ax.transAxes,ax.transData)
plt.setp(ax.get_yticklabels(), 'transform', trans)
plt.show()

How to make a bar chart with only a height indicator not showing the full bar?

This chart almost looks good but is probably not the way to model this in matplotlib. How to have two horizontal bars that extend to the left and right of vertical line at an x-point to show the change of the two datasets eg SDR from 0.7 to 0.25.
Currently i patch things together with '$-$' markers which make misaligned legends and i am not able to place properly. If i change the figsize the markers start misaligning from the vertical bar at their x-point, eg SDR.
How to model this kind of chart proberly?
layer0 = np.random.random(10)
fig, ax = plt.subplots(1,1, figsize=(15/2,1.5*2.5),)
ind = np.arange(10, dtype=np.float64)*1#cordx
ax.plot(ind[0::2]+0.05, layer0[0::2]-0.04, ls='None', marker='$-$', markersize=40)
ax.plot(ind[1::2]-0.15, layer0[1::2]-0.04, ls='None', marker='$-$', markersize=40)
ax.set_ylim(0,1.05)
ax.set_yticks(np.arange(0, 1.1, step=0.1))
ax.set_xticks(ind[0::2]+0.5)
ax.set_xticklabels( ('SDR', 'SSR', 'SCR', 'RCR', 'GUR') )
plt.grid(b=True)
plt.grid(color='black', which='major', axis='y', linestyle='--', lw=0.2)
plt.show()
Alternatively, you can use a horizontal bar chart barh which is more intuitive in this case. Here the key parameter is left which will shift your horizontal bar charts to left/right.
Following is a complete answer:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2)
layer0 = np.random.random(10)
fig, ax = plt.subplots(1,1, figsize=(15/2,1.5*2.5),)
n = 10
width = 0.5
ind = np.arange(n, dtype=np.float64)*1#cordx
ax.barh(layer0[0::2], [width]*int(n/2), height=0.01, left = ind[0::2])
ax.barh(layer0[1::2], [width]*int(n/2), height=0.01, left = ind[0::2]+width)
ax.set_ylim(0,1.05)
ax.set_yticks(np.arange(0, 1.1, step=0.1))
ax.set_xticks(ind[0::2]+0.5)
ax.set_xticklabels( ('SDR', 'SSR', 'SCR', 'RCR', 'GUR') )
plt.grid(b=True)
plt.grid(color='black', which='major', axis='y', linestyle='--', lw=0.2)
plt.show()
up until now i havent thought of bar charts with bottom offset, which seems to be ok:
layer0 = np.random.random(10)
fig, ax = plt.subplots(1,1, figsize=(15/1.3,1.5*2.5),)# sharey=True)
ind = np.arange(10, dtype=np.float64)*1#cordx
height=0.03
width=0.8
ax.bar(ind[0::2]-width/2, height, width=width, bottom=layer0[0::2]-height)
ax.bar(ind[0::2]+width/2, height, width=width, bottom=layer0[1::2]-height)
ax.set_ylim(-0.,1.05)
plt.grid(color='black', which='major', axis='x', linestyle='-', lw=0.8)

How to add a title to each subplot

I have one figure which contains many subplots.
fig = plt.figure(num=None, figsize=(26, 12), dpi=80, facecolor='w', edgecolor='k')
fig.canvas.set_window_title('Window Title')
# Returns the Axes instance
ax = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
How do I add titles to the subplots?
fig.suptitle adds a title to all graphs and although ax.set_title() exists, the latter does not add any title to my subplots.
Thank you for your help.
Edit:
Corrected typo about set_title(). Thanks Rutger Kassies
ax.title.set_text('My Plot Title') seems to work too.
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()
ax.set_title() should set the titles for separate subplots:
import matplotlib.pyplot as plt
if __name__ == "__main__":
data = [1, 2, 3, 4, 5]
fig = plt.figure()
fig.suptitle("Title for whole figure", fontsize=16)
ax = plt.subplot("211")
ax.set_title("Title for first plot")
ax.plot(data)
ax = plt.subplot("212")
ax.set_title("Title for second plot")
ax.plot(data)
plt.show()
Can you check if this code works for you? Maybe something overwrites them later?
A shorthand answer assuming
import matplotlib.pyplot as plt:
plt.gca().set_title('title')
as in:
plt.subplot(221)
plt.gca().set_title('title')
plt.subplot(222)
etc...
Then there is no need for superfluous variables.
If you want to make it shorter, you could write :
import matplotlib.pyplot as plt
for i in range(4):
plt.subplot(2,2,i+1).set_title(f'Subplot n°{i+1}')
plt.show()
It makes it maybe less clear but you don't need more lines or variables
A solution I tend to use more and more is this one:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 2) # 1
for i, ax in enumerate(axs.ravel()): # 2
ax.set_title("Plot #{}".format(i)) # 3
Create your arbitrary number of axes
axs.ravel() converts your 2-dim object to a 1-dim vector in row-major style
assigns the title to the current axis-object
fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=1, ncols=4,figsize=(11, 7))
grid = plt.GridSpec(2, 2, wspace=0.2, hspace=0.5)
ax1 = plt.subplot(grid[0, 0])
ax2 = plt.subplot(grid[0, 1:])
ax3 = plt.subplot(grid[1, :1])
ax4 = plt.subplot(grid[1, 1:])
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()
In case you have multiple images and you want to loop though them and show them 1 by 1 along with titles - this is what you can do. No need to explicitly define ax1, ax2, etc.
The catch is you can define dynamic axes(ax) as in Line 1 of code
and you can set its title inside a loop.
The rows of 2D array is length (len) of axis(ax)
Each row has 2 items i.e. It is list within a list (Point No.2)
set_title can be used to set title, once the proper axes(ax) or subplot is selected.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(6, 8))
for i in range(len(ax)):
for j in range(len(ax[i])):
## ax[i,j].imshow(test_images_gr[0].reshape(28,28))
ax[i,j].set_title('Title-' + str(i) + str(j))
You are able to give every graph a different title and label by Iteration only.
titles = {221: 'First Plot', 222: 'Second Plot', 223: 'Third Plot', 224: 'Fourth Plot'}
fig = plt.figure()
for x in range(221,225):
ax = fig.add_subplot(x)
ax.title.set_text(titles.get(x))
plt.subplots_adjust(left=0.1,
bottom=0.1,
right=0.9,
top=0.9,
wspace=0.4,
hspace=0.4)
plt.show()
Output:
As of matplotlib 3.4.3, the Figure.add_subplot function supports kwargs with title as:
fig.add_subplot(311, title="first")
fig.add_subplot(312, title="second")
For completeness, the requested result can also be achieve without explicit reference to the figure axes as follows:
import matplotlib.pyplot as plt
plt.subplot(221)
plt.title("Title 1")
plt.subplot(222)
plt.title("Title 2")
plt.subplot(223)
plt.title("Title 3")
plt.subplot(224)
plt.title("Title 4")
Use plt.tight_layout() after the last plot if you have issues with overlapping labels.

Categories