Search code examples
pythonmatplotlibresolution

How to preserve the resolution when adding axis using matplotlib.pyplot?


If the following code is run

import matplotlib.pyplot as plt
import numpy as np
a=np.random.random((1000,1000))
plt.imshow(a, cmap='Reds', interpolation='nearest')
plt.savefig('fig.png',bbox_inches='tight')

I got the picture below, with all the cells representing each random number.

enter image description here

However, when the axis is added as the code shown below:

import matplotlib.pyplot as plt
import numpy as np
a=np.random.random((1000,1000))
plt.imshow(a, cmap='Reds', interpolation='nearest')

plt.xlim(0, 10)
plt.xticks(list(range(0, 10)))
plt.ylim(0, 10)
plt.yticks(list(range(0, 10)))

plt.savefig('fig3.png',bbox_inches='tight')

I got the picture with less resolution:

enter image description here

So how can I add axis ticks without affecting the resolution? If this is related to the font size of axis markers, how to automatically adjust them so as to keep the original resolution?


Solution

  • Application to your problem:

    from matplotlib.ticker import FuncFormatter
    from matplotlib.pyplot import show
    import matplotlib.pyplot as plt
    import numpy as np
    
    a=np.random.random((1000,1000))
    
    # create scaled formatters / for Y with Atom prefix
    formatterY = FuncFormatter(lambda y, pos: 'Atom {0:g}'.format(y*0.01))
    formatterX = FuncFormatter(lambda x, pos: '{0:g}'.format(x*0.01))
    
    # apply formatters 
    fig, ax = plt.subplots()
    ax.yaxis.set_major_formatter(formatterY)
    ax.xaxis.set_major_formatter(formatterX)
    
    plt.imshow(a, cmap='Reds', interpolation='nearest')
    
    # create labels
    plt.xlabel('nanometer')
    plt.ylabel('measure')
    plt.xticks(list(range(0, 1001,100)))
    
    plt.yticks(list(range(0, 1001,100)))
    
    plt.show()
    

    Y with Atoms, X with scalen numbers, both with titles

    Sources:

    A possible solution is to format the ticklabels according to some function as seen in below example code from the matplotlib page.

    from matplotlib.ticker import FuncFormatter
    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.arange(4)
    money = [1.5e5, 2.5e6, 5.5e6, 2.0e7]
    
    
    def millions(x, pos):
        'The two args are the value and tick position'
        return '$%1.1fM' % (x * 1e-6)
    
    
    formatter = FuncFormatter(millions)
    
    fig, ax = plt.subplots()
    ax.yaxis.set_major_formatter(formatter)
    plt.bar(x, money)
    plt.xticks(x, ('Bill', 'Fred', 'Mary', 'Sue'))
    plt.show()
    

    matplotlib.org Example


    A similar solution is shown in this answer, where you can set a function to label the axis for you and scale it down:

    ticks = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x*scale))
    ax.xaxis.set_major_formatter(ticks)
    

    Here, you would need to do /100 instead of *scale

    The easier way for yours would probably be:

    ticks = plt.xticks()/100
    plt.gca().set_xticklabels(ticks.astype(int))
    

    (adapted from https://stackoverflow.com/a/10171851/7505395)