Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

matplotlib matshow xtick labels on top and bottom

I'm trying to visualize a name co-occurrence matrix. This version works okay:

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

n = 10
names = ['Long Name ' + suffix for suffix in string.ascii_uppercase[:n]]
df = pd.DataFrame(np.random.randint(0, 100, size=(n,n)),
                  columns=names, index=names)

fig = plt.figure()
ax = plt.gca()

im = ax.matshow(df, interpolation='none')
fig.colorbar(im)

ax.set_xticks(np.arange(n))
ax.set_xticklabels(names)
ax.set_yticks(np.arange(n))
ax.set_yticklabels(names)
ax.xaxis.set_ticks_position("bottom")
plt.setp(ax.get_xticklabels(), rotation=45,
         ha="right", rotation_mode="anchor")

for (i,j), z in np.ndenumerate(df):
  if z != 0:
    ax.text(j, i, str(z), ha="center", va="center")

ax.set_title("Name Co-Occurrences")
fig.tight_layout()
plt.show()

The problem is that the actual matrix I have is fairly large, so I would like to display the names both on the top and the bottom. I've tried to do so by using twiny:

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

n = 10
names = ['Long Name ' + suffix for suffix in string.ascii_uppercase[:n]]
df = pd.DataFrame(np.random.randint(0, 100, size=(n,n)),
                  columns=names, index=names)

fig = plt.figure()
botax = plt.gca()

im = botax.matshow(df, interpolation='none')
fig.colorbar(im)

topax = botax.twiny()
for ax, ha, pos in zip([topax, botax], ["left", "right"], ["top", "bottom"]):
  ax.set_xticks(np.arange(n))
  ax.set_xticklabels(names)
  ax.set_yticks(np.arange(n))
  ax.set_yticklabels(names)
  ax.xaxis.set_ticks_position(pos)
  plt.setp(ax.get_xticklabels(), rotation=45,
           ha=ha, va="center", rotation_mode="anchor")

for (i,j), z in np.ndenumerate(df):
  if z != 0:
    botax.text(j, i, str(z), ha="center", va="center")

botax.set_title("Name Co-Occurrences")
fig.tight_layout()
plt.show()

Unfortunately the top labels aren't aligned correctly and I don't know why: Misaligned X tick labels

like image 532
Robert Utterback Avatar asked Dec 13 '22 12:12

Robert Utterback


2 Answers

In order to label both, bottom and top of an axes, there is no need for a twin axes. This may make this all a bit easier. You can instead just turn the bottom and top ticks and labels on, and then rotate and align them separately.

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

n = 10
names = ['Long Name ' + suffix for suffix in string.ascii_uppercase[:n]]
df = pd.DataFrame(np.random.randint(0, 100, size=(n,n)),
                  columns=names, index=names)

fig = plt.figure()
ax = plt.gca()

im = ax.matshow(df, interpolation='none')
fig.colorbar(im)

ax.set_xticks(np.arange(n))
ax.set_xticklabels(names)
ax.set_yticks(np.arange(n))
ax.set_yticklabels(names)

# Set ticks on both sides of axes on
ax.tick_params(axis="x", bottom=True, top=True, labelbottom=True, labeltop=True)
# Rotate and align bottom ticklabels
plt.setp([tick.label1 for tick in ax.xaxis.get_major_ticks()], rotation=45,
         ha="right", va="center", rotation_mode="anchor")
# Rotate and align top ticklabels
plt.setp([tick.label2 for tick in ax.xaxis.get_major_ticks()], rotation=45,
         ha="left", va="center",rotation_mode="anchor")

ax.set_title("Name Co-Occurrences", pad=55)
fig.tight_layout()
plt.show()

enter image description here

like image 122
ImportanceOfBeingErnest Avatar answered Jan 02 '23 16:01

ImportanceOfBeingErnest


You will have to first set the aspect ratio of the upper x-axis to be the same as that of the lower x-axis. How to do this has been answered here. Then you can use y=1.3 to lift the title a bit upward so that it does not overlap with the upper x-axis tick labels.

topax = botax.twiny()

aspect0 = botax.get_aspect()
if aspect0 == 'equal':
    aspect0 = 1.0
dy = np.abs(np.diff(botax.get_ylim()))
dx = np.abs(np.diff(botax.get_xlim()))

aspect = aspect0 / (float(dy) / dx)
topax.set_aspect(aspect)

for ax, ha, pos in zip([topax, botax], ["left", "right"], ["top", "bottom"]):
  ax.set_xticks(np.arange(n))
  .....
  .....

botax.set_title("Name Co-Occurrences", y=1.3)

enter image description here

like image 32
Sheldore Avatar answered Jan 02 '23 16:01

Sheldore