I need to specify ticks formatter for each plot of several subplots:
import numpy as np
import pylab as plt
import matplotlib.ticker as ticker
x = np.arange(10)
y = x
fig = plt.figure()
for i in [1, 2, 3]:
ax = fig.add_subplot(3, 1, i)
ax.plot(x, y)
ticks = ticker.FuncFormatter(lambda x, pos: '{}:{:g}'.format(i, x))
ax.xaxis.set_major_formatter(ticks)
plt.show()
But only the last (bottom) fotmatter is used for all other plots. What I do wrong?
You can use a ticker.FormatStrFormatter object as shown below.
I believe the problem with your original approach was that you were setting the Formatter for each axis to the tick variable and then overwriting it on the next iteration, as such all your graphs were using the tick variable from the last iteration.
When you create Formatter objects you have to have one for each subplot, in my code below it's not a problem because I don't assign the FormatStrFormatter to a variable.
import numpy as np
import pylab as plt
import matplotlib.ticker as ticker
x = np.arange(10)
y = x
fig, axes = plt.subplots(nrows=3, ncols=1)
for i, ax in enumerate(axes):
ax.plot(x, y)
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('{}:%d'.format(i+1)))
plt.show()
EDIT
Here is a version which uses the original FuncFormatter formatter object. The map method creates three separate ticker objects from their associated lambda functions. The for loop iterates over both ax and tick to assign each subplot.
import numpy as np
import pylab as plt
import matplotlib.ticker as ticker
x = np.arange(10)
y = x
fig, axes = plt.subplots(nrows=3, ncols=1)
def create_ticker(i):
# Create a FuncFormatter.
return ticker.FuncFormatter(lambda x, pos: '{}:{:g}'.format(i+1, x))
ticks = map(create_ticker, range(3))
for ax, tick in zip(axes, ticks):
ax.plot(x, y)
ax.xaxis.set_major_formatter(tick)
plt.show()
Related
I want to hide the x,y axes values as highlighted in the figure. Is it possible to do it? I also attach the expected representation.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
n=3
X = np.arange(n)
Y = -X
x_sorted = np.sort(X)
y_sorted = np.sort(Y)
ax.set_xticks(x_sorted)
ax.set_yticks(y_sorted)
ax.set_xlim(x_sorted[0], x_sorted[-1])
ax.set_ylim(y_sorted[0], y_sorted[-1])
ax.grid()
ax.set_aspect('equal', 'box')
plt.show()
The expected representation is
You need to empty x and y tick labels from ax variable:
ax.set_yticklabels([])
ax.set_xticklabels([])
I have the following plot:
How can I increase the space among values in X axis with matplotlib?
Thanks!
You can set a log scale and invert the x-axis:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import ScalarFormatter
x = [round(28800 * 2 ** (-i)) for i in range(10)]
y = np.random.randint(0, 80, len(x))
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_xscale('log')
ax.set_xticks(x)
ax.xaxis.set_major_formatter(ScalarFormatter())
ax.invert_xaxis()
plt.show()
This is a simplified example of a problem I am having.
import matplotlib.pyplot as plt
for i in range(0,10):
plt.plot(i, i + 1)
plt.show()
shows this. and
x = y = []
for i in range(0,10):
x.append(i)
y.append(i + 1)
plt.plot(x, y,)
plt.show()
shows this.
How can I plot points in a loop so that I don't need to create two arrays?
Try this-
import matplotlib.pyplot as plt
for i in range(0,10):
plt.plot(i, i + 1, color='green', linestyle='solid', linewidth = 3,
marker='o')
plt.show()
Pass array as the first argumet to plt.plot(), this would plot y using x as index array 0..N-1:
import matplotlib.pyplot as plt
# plot y using x as index array 0..N-1
plt.plot(range(10))
plt.show()
You'll find more interesting information at plt.plot().
You can do it with:
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
fig, ax = plt.subplots()
max =10
for i in range(0,max):
#scatter:
#s=0 to make dissapeared the scatters
ax.scatter(i, i + 1,s=1,facecolor='blue')
#lines
if i > 0:
lc = LineCollection([[(i-1, i),(i, i+1)]])
ax.add_collection(lc)
plt.show()
result:
Let suppose I have a matplotlib's gridspec instance in a python script. What I want to do is to create two axis and have the plot in one axis and the legend in the other one. Something like
import numpy as np
from matplotlib import gridspec, pyplot as plt
x = np.linspace(0,100)
y = np.sin(x)
gs = gridspec.GridSpec( 100, 100 )
ax1 = fig.add_subplot(gs[ :50, : ])
ax2 = fig.add_subplot(gs[ 55:, : ])
ax1.plot( s, y, label=r'sine' )
ax2.legend() # ?? Here I want legend of ax1
plt.show()
Is there any way of doing that?
You can grab the legend handles and labels from the first subplot using ax1.get_legend_handles_labels(), and then use them when you create the legend on the second subplot.
From the docs:
get_legend_handles_labels(legend_handler_map=None)
Return handles and labels for legend
ax.legend() is equivalent to:
h, l = ax.get_legend_handles_labels()
ax.legend(h, l)
import numpy as np
from matplotlib import gridspec, pyplot as plt
x = np.linspace(0, 100)
y = np.sin(x)
fig = plt.figure()
gs = gridspec.GridSpec(100, 100 )
ax1 = fig.add_subplot(gs[:50, :])
ax2 = fig.add_subplot(gs[55:, :])
ax1.plot(x, y, label=r'sine')
h, l = ax1.get_legend_handles_labels() # get labels and handles from ax1
ax2.legend(h, l) # use them to make legend on ax2
plt.show()
I have a very simple question. I need to have a second x-axis on my plot and I want that this axis has a certain number of tics that correspond to certain position of the first axis.
Let's try with an example. Here I am plotting the dark matter mass as a function of the expansion factor, defined as 1/(1+z), that ranges from 0 to 1.
semilogy(1/(1+z),mass_acc_massive,'-',label='DM')
xlim(0,1)
ylim(1e8,5e12)
I would like to have another x-axis, on the top of my plot, showing the corresponding z for some values of the expansion factor. Is that possible? If yes, how can I have xtics ax
I'm taking a cue from the comments in #Dhara's answer, it sounds like you want to set a list of new_tick_locations by a function from the old x-axis to the new x-axis. The tick_function below takes in a numpy array of points, maps them to a new value and formats them:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
X = np.linspace(0,1,1000)
Y = np.cos(X*20)
ax1.plot(X,Y)
ax1.set_xlabel(r"Original x-axis: $X$")
new_tick_locations = np.array([.2, .5, .9])
def tick_function(X):
V = 1/(1+X)
return ["%.3f" % z for z in V]
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(new_tick_locations)
ax2.set_xticklabels(tick_function(new_tick_locations))
ax2.set_xlabel(r"Modified x-axis: $1/(1+X)$")
plt.show()
You can use twiny to create 2 x-axis scales. For Example:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
a = np.cos(2*np.pi*np.linspace(0, 1, 60.))
ax1.plot(range(60), a)
ax2.plot(range(100), np.ones(100)) # Create a dummy plot
ax2.cla()
plt.show()
Ref: http://matplotlib.sourceforge.net/faq/howto_faq.html#multiple-y-axis-scales
Output:
From matplotlib 3.1 onwards you may use ax.secondary_xaxis
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1,13, num=301)
y = (np.sin(x)+1.01)*3000
# Define function and its inverse
f = lambda x: 1/(1+x)
g = lambda x: 1/x-1
fig, ax = plt.subplots()
ax.semilogy(x, y, label='DM')
ax2 = ax.secondary_xaxis("top", functions=(f,g))
ax2.set_xlabel("1/(x+1)")
ax.set_xlabel("x")
plt.show()
If You want your upper axis to be a function of the lower axis tick-values you can do as below. Please note: sometimes get_xticks() will have a ticks outside of the visible range, which you have to allow for when converting.
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
ax1 = fig.add_subplot(111)
ax1.plot(range(5), range(5))
ax1.grid(True)
ax2 = ax1.twiny()
ax2.set_xticks( ax1.get_xticks() )
ax2.set_xbound(ax1.get_xbound())
ax2.set_xticklabels([x * 2 for x in ax1.get_xticks()])
title = ax1.set_title("Upper x-axis ticks are lower x-axis ticks doubled!")
title.set_y(1.1)
fig.subplots_adjust(top=0.85)
fig.savefig("1.png")
Gives:
Answering your question in Dhara's answer comments: "I would like on the second x-axis these tics: (7,8,99) corresponding to the x-axis position 10, 30, 40. Is that possible in some way?"
Yes, it is.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
a = np.cos(2*np.pi*np.linspace(0, 1, 60.))
ax1.plot(range(60), a)
ax1.set_xlim(0, 60)
ax1.set_xlabel("x")
ax1.set_ylabel("y")
ax2 = ax1.twiny()
ax2.set_xlabel("x-transformed")
ax2.set_xlim(0, 60)
ax2.set_xticks([10, 30, 40])
ax2.set_xticklabels(['7','8','99'])
plt.show()
You'll get:
I'm forced to post this as an answer instead of a comment due to low reputation.
I had a similar problem to Matteo. The difference being that I had no map from my first x-axis to my second x-axis, only the x-values themselves. So I wanted to set the data on my second x-axis directly, not the ticks, however, there is no axes.set_xdata. I was able to use Dhara's answer to do this with a modification:
ax2.lines = []
instead of using:
ax2.cla()
When in use also cleared my plot from ax1.