开发者

How to add constant-spaced ticks on axes whose lenghts vary? [Python]

To simplify my problem (it's not exactly like that but I prefer simple answers to simple questions):

I have several 2D maps that portray rectangular region areas. I'd like to add on the map axes and ticks to show the distances on this map (with matplotlib, since the old code is with it), but the problem is that the areas are different sized. I'd like to put on the axes nice, clear ticks, but the widths and heights of the maps can be anything...

To try to explain what I mean: Let's say I have a map of a region whose size is 4.37 km * 6.42 km. I want that there is on x-axis ticks on 0, 1, 2, 3, and 4 km:s and on y-axis ticks on 0, 1, 2, 3, 4, 5, and 6 km:s. However, the image and the axes reach a bit further than to 4 km and 6 km, since the region is larger then 4 km * 6 km.

The space between the ticks can be constant, 1 km. However, the sizes of the maps vary quite a lot (let's say, between 5-15 km), and they are float values. My current script knows the size of the region and can scale the image into right height/width ratio, but how to tell it where to put the ticks?

There may be already solution for this problem, but 开发者_如何学Pythonsince I couldn't find suitable search words for my problem, I had to ask it here...


Just set the tick locator to use matplotlib.ticker.MultipleLocator(x) where x is the spacing that you want (e.g. 1.0 in your example above).

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter

x = np.arange(20)
y = x * 0.1

fig, ax = plt.subplots()
ax.plot(x, y)

ax.xaxis.set_major_locator(MultipleLocator(1.0))
ax.yaxis.set_major_locator(MultipleLocator(1.0))

# Forcing the plot to be labeled with "plain" integers instead of scientific notation
ax.xaxis.set_major_formatter(FormatStrFormatter('%i'))

plt.show()

The advantage to this is that no matter how we zoom or interact with the plot, it will always be labeled with ticks 1 unit apart.

How to add constant-spaced ticks on axes whose lenghts vary? [Python]


This should give you ticks at all integer values within your current axis limits on the x axis:

from matplotlib import pylab as plt
import math

# get values for the axis limits (unless you already have them)
xmin,xmax = plt.xlim()

# get the outermost integer values using floor and ceiling 
# (I need to convert them to int to avoid a DeprecationWarning),
# then get all the integer values between them using range
new_xticks = range(int(math.ceil(xmin)),int(math.floor(xmax)+1))
plt.xticks(new_xticks,new_xticks)
# passing the same argment twice here because the first gives the tick locations
# and the second gives the tick labels, which should just be the numbers

Repeat for the y axis.

Out of curiosity: what kind of ticks do you get by default?


Okay, I tried your versions, but unfortunately I couldn't make them work, since there was some scaling and PDF locating stuff that made me (and your code suggestions) badly confused. But by testing them, I learned again a lot of python, thanks!

I managed finally to find a solution that isn't very exact but satisfies my needs. Here is how I did it.

In my version, one km is divided by a suitable integer constant named STEP_PART. The bigger is STEP_PART, the more accurate the axis values are (and if it is too big, the axis becomes messy to read). For example, if STEP_PART is 5, the accuracy is 1 km / 5 = 200 m, and ticks are put to every 200 m.

STEP_PART = 5             # In the start of the program.

height = 6.42             # These are actually given elsewhere,
width = 4.37              # but just as example...

vHeight = range(0, int(STEP_PART*height), 1)  # Make tick vectors, now in format
                                              # 0, 1, 2... instead of 0, 0.2...
vWidth = range(0, int(STEP_PART*width), 1)    # Should be divided by STEP_PART 
                                              # later to get right values.

To avoid making too many axis labels (0, 1, 2... are enough, 0, 0.2, 0.4... is far too much), we replace non-integer km values with string "". Simultaneously, we divide integer km values by STEP_PART to get right values.

for j in range(len(vHeight)):
    if (j % STEP_PART != 0):
        vHeight[j] = ""
    else:
        vHeight[j] = int(vHeight[j]/STEP_PART)

for i in range(len(vWidth)):
    if (i % STEP_PART != 0):
        vWidth[i] = ""
    else:
        vWidth[i] = int(vWidth[i]/STEP_PART)

Later, after creating the graph and axes, ticks are put in that way (x axis as an example). There, x is the actual width of the picture, got with shape() command (I don't exactly understand how... there is quite a lot scaling and stuff in the code I'm modifying).

xt = np.linspace(0,x-1,len(vWidth)+1) # For locating those ticks on the same distances.
locs, labels = mpl.xticks(xt, vWidth, fontsize=9) 

Repeat for y axis. The result is a graph where is ticks on every 200 m's but data labels on the integer km values. Anyway, the accuracy of those axes are 200 m's, it's not exact but it was enough for me. The script will be even better if I find out how to grow the size of the integer ticks...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜