How do I change the text of the x axis? - python

I have the following graph:
As you can see, the x-axis has the increments of 2000. The x-axis values are time, and I had to make changes to the time values to get them to work properly. An example of the x values (time list) is:
t_list = [13264,13273,13.279,13.301...]
I want to the x-axis to be in increments of 0.1, and change the values in the time list to be as follows:
t_list = [13.264,13.643,13.689,13.701...]
And I only want the x-axis to display the first decimal, but also include a "1:" with it (1:13.1, 1:13.2,1:13.3,etc.)
How can I achieve this?

You can use a locator to tell where to put the ticks, e.g. multiples of 100.
And a formatter to tell how to display the values:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
fig, ax = plt.subplots(figsize=(15, 2))
ax.plot([13100, 22000], [1, 1])
ax.xaxis.set_major_locator(MultipleLocator(100))
ax.xaxis.set_major_formatter(lambda x, pos: f'1:{x / 1000:.1f}')
ax.tick_params(axis='x', rotation=90) # optionally rotate the ticks
plt.tight_layout()
plt.show()
You can also combine minor and major ticks. Here is an example:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
fig, ax = plt.subplots(figsize=(15, 2))
ax.plot([13100, 22000], [1, 1])
ax.xaxis.set_major_locator(MultipleLocator(1000))
ax.xaxis.set_major_formatter(lambda x, pos: f'1:{x / 1000:.0f}')
ax.xaxis.set_minor_locator(MultipleLocator(100))
ax.xaxis.set_minor_formatter(lambda x, pos: f'.{(x / 100) % 10:.0f}')
ax.tick_params(axis='x', which='major', labelsize=12, length=12)
ax.tick_params(axis='x', which='minor', labelsize=9)
plt.tight_layout()
plt.show()

Related

How do I change the units shown on the x-axis labels on a Matplotlib bar chart

I'm trying to make it so the ticks on the x-axis for revenue show the value as a factor of a million rather than as a factor of a hundred million as they are now. I can't seem to figure out how to accomplish this. My code and the resulting bar chart is below.
import numpy as np
import pandas as pd
import matplotlib.ticker as plticker
import matplotlib.pyplot as plt
import seaborn as sns
from IPython.display import display
from pandas import Series
%matplotlib inline
# Define Figure Size
fig, ax = plt.subplots(figsize=(25,25))
# Get the average vote_average for each genre
average_revenue = df2.groupby('release_year')['revenue_adj'].mean()
# Find positions of y ticks
y_pos = np.arange(len(df2['release_year'].unique()))
# Set up Bar Chart
ax.set_yticks(y_pos)
ax.set_yticklabels(sorted(df2['release_year'].unique()))
ax.set_xlabel('Revenue in Millions', fontsize=16)
ax.set_ylabel('Release Year', fontsize=16)
ax.set_title('Revenue by Release Year', fontsize=20)
# Set Size of X and Y labels
plt.rc('xtick', labelsize=14)
plt.rc('ytick', labelsize=14)
# Put Values next to Each Bar
for i, v in enumerate(average_revenue):
a = v/1000000
ax.text(v, i, ('$' + str(round(a,2)) + 'M'), color='blue')
ax.invert_yaxis() # labels read top-to-bottom
# Draw Bar Chart
ax.barh(y_pos, average_revenue, align='center', color='green', ecolor='black')
Right now, the data is shown in ones, not millions or hundreds of millions. Notice the 1e8 on the right of the plot. You can plot the value in millions by dividing the input by a million:
ax.barh(y_pos, average_revenue * 1e-6, ...)
Alternatively, you can adjust the formatter on the x-axis if you prefer not to alter the data. For example, you could use a FuncFormatter like this:
from matplotlib.ticker import FuncFormatter
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: f'{x * 1e-6:0.1f}'))

Rotation of colorbar tick labels in matplotlib resets tick label formatting

If I do rotation to the colorbar labels, the format I used seem to be reset (ignored).
The fig.colorbar does not accept rotation, while cb.ax.set_xticklabels does not accept format.
I couldn't find any way to do both settings.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.ticker import FormatStrFormatter
test = np.random.rand(100, 100)
np.random.seed(12345)
fig, axs = plt.subplots(1, 2, figsize=(6, 5))
fmts = ["%d", "%.5f"]
for i, ax in enumerate(axs.tolist()):
im = ax.imshow(test, origin="lower")
cb = fig.colorbar(im, ax=ax, orientation='horizontal',
format=FormatStrFormatter(fmts[i]))
ax.set_title(f"Format {fmts[i]}")
cb.ax.set_xticklabels(cb.get_ticks(), rotation=45)
plt.tight_layout()
plt.show()
The colorbar tick labels should be in the format of "%d" and "%.5f" but as you can see, neither does.
I don't think that the original formatting is kept when you call cb.ax.set_xticklabels(), you could add cb.ax.xaxis.set_major_formatter(FormatStrFormatter(fmts[i])) to re-apply the custom formatting afterwards.
As an alternative, use plt.setp(cb.ax.get_xticklabels(),rotation=45) instead to rotate the labels.

Seaborn gives wrong values on x-axis ticks?

In the code below Matplotlib gives the correct range of 5.0 to 10.0, why is Seaborn different?
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from matplotlib import ticker
sns.set()
fig, (ax1, ax2) = plt.subplots(2)
x = np.linspace(5, 10)
y = x ** 2
sns.barplot(x, y, ax=ax1)
ax1.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax1.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
ax2.bar(x, y, width = 0.1)
ax2.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax2.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
plt.show()
Seaborn's barplot is a categorical plot. This means it places the bars at successive integer positions (0,1,...N-1). Hence, if you have N bars, the axis will range from -0.5 to N-0.5.
There is no way to tell seaborn to place the bars at different positions; but you can of course fake the labels to let it appear as such. E.g. to label every 5th bar with the value from x:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from matplotlib import ticker
sns.set()
fig, ax = plt.subplots()
x = np.linspace(5, 10)
y = x ** 2
sns.barplot(x, y, ax=ax)
ax.xaxis.set_major_locator(ticker.FixedLocator(np.arange(0, len(x), 5)))
ax.xaxis.set_major_formatter(ticker.FixedFormatter(x[::5]))
ax.tick_params(axis="x", rotation=90)
plt.tight_layout()
plt.show()
Inversely, it is possible to plot categorical plots with matplotlib. To this end, one needs to plot strings.
ax.bar(x.astype(str), y)
ax.xaxis.set_major_locator(ticker.FixedLocator(np.arange(0, len(x), 5)))
ax.xaxis.set_major_formatter(ticker.FixedFormatter(x[::5]))
ax.tick_params(axis="x", rotation=90)
If you want a numerical bar plot, i.e. a plot where each bar is at the axis position of x, you would need to use matplotlib. This is the default case also shown in the question, where the bars range between 5 and 10. One should make sure to have the width of the bars smaller than the difference between successive x positions in this case.
ax.bar(x, y, width=np.diff(x).mean()*0.8)
ax.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
ax.tick_params(axis="x", rotation=90)

Matplotlib: Set manual x-axis labels given string label array input, but only on major ticks

I tried this but the labels are not printing in the right location. Some of the labels are not printed and are not printed in the right position.
I have an array of labels that correspond to each data point. I only want some of the labels to be printed and printed only on major ticks. But I do not know how to set major ticks and still keep the labels in correct positions.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
fig, ax1 = plt.subplots(1, 1)
top = np.arange(100)
btm = top-2
x = np.arange(len(top))
ax1.vlines(x, top, btm, color='r', linewidth=1)
labels = np.linspace(200,300,100).astype(np.int).astype(np.str)
factor = 10
labels = [label for i,label in enumerate(labels) if ((i+1)%factor==1)]
plt.xticks(x, labels, rotation='horizontal')
from matplotlib.ticker import MultipleLocator, FormatStrFormatter, FixedFormatter
majorLocator = MultipleLocator(factor)
majorFormatter = FixedFormatter(labels)
minorLocator = MultipleLocator(1)
ax1.xaxis.set_minor_locator(minorLocator)
ax1.xaxis.set_major_formatter(majorFormatter)
ax1.xaxis.set_major_locator(majorLocator)
plt.tick_params(axis='both', which='major', labelsize=9, length=10)
plt.tick_params(axis='both', which='minor', labelsize=5, length=4)
Help. Thanks.
EDIT:
The labels array is of the same length as the number of data points, which is equal to the length of the x axis. So for every increment in position of the x-axis I have the corresponding label. So for the ith position or tick on the x-axis should have either an empty label or the label equal to ith element of label array. It should be empty if it does not fall on a major tick. The labels are not simply integers, but strings. To be more specific, they are datetime strings.
Without a clear problem description, I need to guess that the following might be what you want:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.ticker import MultipleLocator
fig, ax1 = plt.subplots(1, 1)
top = np.arange(100)
btm = top-2
x = np.arange(len(top))
ax1.vlines(x+200, top, btm, color='r', linewidth=1)
majorLocator = MultipleLocator(10)
minorLocator = MultipleLocator(1)
ax1.xaxis.set_major_locator(majorLocator)
ax1.xaxis.set_minor_locator(minorLocator)
plt.tick_params(axis='both', which='major', labelsize=9, length=10)
plt.tick_params(axis='both', which='minor', labelsize=5, length=4)
plt.show()
You can also use a FuncFormatter for the ticklabels.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, FuncFormatter
fig, ax1 = plt.subplots(1, 1)
top = np.arange(100)
btm = top-2
x = np.arange(len(top))
ax1.vlines(x, top, btm, color='r', linewidth=1)
majorLocator = MultipleLocator(10)
minorLocator = MultipleLocator(1)
ax1.xaxis.set_major_locator(majorLocator)
ax1.xaxis.set_minor_locator(minorLocator)
fmt = lambda x,pos : str(int(x+200))
ax1.xaxis.set_major_formatter(FuncFormatter(fmt))
plt.tick_params(axis='both', which='major', labelsize=9, length=10)
plt.tick_params(axis='both', which='minor', labelsize=5, length=4)
plt.show()
What I needed was the FixedLocator with the FixedFormatter, and also an array of integers, majorpos, which specify the indices where the major ticks are located.
The other answer using FuncFormatter would introduce some problems.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
fig, ax1 = plt.subplots(1, 1)
top = np.arange(100)
btm = top-2
x = np.arange(len(top))
ax1.vlines(x, top, btm, color='r', linewidth=1)
labels = np.linspace(200,300,100).astype(np.int).astype(np.str)
print(labels)
factor = 10
plt.xticks(x, labels, rotation='horizontal')
from matplotlib.ticker import MultipleLocator, FormatStrFormatter, FixedFormatter, FixedLocator
majorpos = np.arange(0,len(labels),int(len(labels)/10))
ax1.xaxis.set_major_locator(FixedLocator((majorpos)))
ax1.xaxis.set_major_formatter(FixedFormatter((labels[majorpos])))
ax1.xaxis.set_minor_locator(MultipleLocator(1))
plt.tick_params(axis='both', which='major', labelsize=9, length=10)
plt.tick_params(axis='both', which='minor', labelsize=5, length=4)

How to avoid negative numbers on axis in matplotlib scatterplot

I am doing a simple scatterplot using Pythons scatterplot. But no matter how I set my axis, and no matter that I don't have any negative values I get negative values at the x-axis. How do I force the axis to start at 0?
My code:
fig, ax = plt.subplots(1)
ax.scatter(lengths,breadths, alpha=0.3, color="#e74c3c", edgecolors='none')
spines_to_remove = ['top', 'right']
for spine in spines_to_remove:
ax.spines[spine].set_visible(False)
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
ax.xaxis.set_view_interval(0,400)
ax.yaxis.set_view_interval(0,90)
figname = 'scatterlengthsbreadths.pdf'
fig.savefig(figname, bbox_inches='tight')
You can use ax.set_xlim(lower_limit, upper_limit) to choose your x-limits. Note that there is a similar command ax.set_ylim for the y-limits.
Note that if you're just using the pyplot interface, i.e. without using fig and ax, then the command is plt.xlim().
For example:
import matplotlib.pyplot as plt
x = [1,2,3]
y = [4,5,6]
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_xlim(0, 10)
plt.show()

Categories

Resources