PgfPlots: Scale X-Axis Non-linearly

I want to scale x-axis in a non-linear way. That is, for example, I want to have ticks 1,2,45,100,400 with equal distance between each of them. The scale between 1 and 2 , 2 and 45, etc., should be linear. I have searched internet extensively but couldn't find a clue.

• This may sound like a silly question, but will you have data points only at the ticks, or can there be datapoints for e.g. x=300 in your example? Commented Oct 10, 2015 at 22:32
• @Bronsteinx you can use xtick and ytick options for axis environment. Look pgfplots guide. Commented Oct 11, 2015 at 5:13
• @Torbjørn T., there will be other data points. Commented Oct 11, 2015 at 7:52
• @juanuni, are you sure it works ? I think xtick will not change scale of the axis, but it will only put ticks at specified points. I will try however. Commented Oct 11, 2015 at 7:56
• No, @juanuni's suggestion will not work. Commented Oct 11, 2015 at 8:14

While it probably is possible to do this in LaTeX alone, I'm lazy, and use Python with Numpy to create new x-values. This is assuming you have a data file with two columns of numbers, for x and y. I've added comments in the Python code, ask if anything is unclear.

# I'm using Python 3, but I think this line will make it work with Python 2.x
from __future__ import division
# numpy for number juggling, sys to get arguments from command line
import numpy as np
import sys

# read the two columns from the specified file into x and y

# read tick locations from second argument and convert from str to float
ticks = sys.argv[2]
ticks = [float(i) for i in ticks.split(',')]

# in the case that the data are outside the specified tick locations,
# add a new tick for the smallest and/or largest x-value
if x[0] < ticks[0]:
ticks = [x[0]] + ticks
if x[-1] > ticks[-1]:
ticks = ticks + [x[-1]]

# make a new x-vector including tick locations, and interpolate y-values to tick locs
newx = np.unique((np.concatenate((x,ticks))))
newy = np.interp(newx,x,y)

# set up array for new x-values
weirdx = np.empty_like(newx)

for i in range(len(ticks)-1):
# find all x-values that are between two adjacent ticks
I = np.where( (ticks[i] <= newx) & (newx <= ticks[i+1]) )[0]
if len(I) > 0:
# Algorithm:
#   take x values in range and subtract the first value (at first tick), so they start at 0
#   divide by the last value (at last tick), so values run from 0 to 1
#   add i, where i is the number of the first tick (counting from 0)
subx = newx[I]
subx -= subx[0]
subx /= subx[-1]
subx += i
weirdx[I] = subx

# if the ticks are outside the data range, remove the x and y values at the first/last ticks
if x[-1] < ticks[-1]:
weirdx = np.delete(weirdx, -1)
newy = np.delete(newy,-1)
if x[0] > ticks[0]:
weirdx = np.delete(weirdx, 0)
newy = np.delete(newy,0)

# save new data file, and file with tick labels
np.savetxt('newdata.dat',np.hstack(( weirdx[:,np.newaxis], newy[:,np.newaxis] )), '%.8f')
np.savetxt('ticks.dat', ticks, '%u')


Save the script in the same folder as your data file and run

python ticks.py data.dat 1,2,45,200,450


where ticks.py is the name of the script file, data.dat is the name of the data file, and 1,2,... is the list of tick locations. Note that you cannot have spaces in the tick list.

As a test I generated some numbers for a straight line y = 2x, for x between 0 and 495. The output and LaTeX code is below. Note that the locations of the ticks must be specified manually.

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}