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.
1 Answer
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 x,y = np.loadtxt(sys.argv[1],unpack=True) # 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} \pgfplotstableread{newdata.dat}\data \pgfplotstableread{ticks.dat}\ticky \begin{document} \begin{tikzpicture} \begin{axis}[ xticklabels from table={\ticky}{[index]0}, xtick={0,...,6}, grid] \addplot [black] table[x index=0,y index=1] {\data}; \end{axis} \end{tikzpicture} \end{document} 
xtickandytickoptions foraxisenvironment. Look pgfplots guide.