I'm trying to set the x-axis tick label in matplotlib (2.1.0) (Python 3.6.3 | Windows 10) to uppercase by adding the pattern with the flag %^b like this (plot code):
ax.xaxis.set_minor_formatter(mdates.DateFormatter('%^b'))
However I'm getting the error
ValueError: Invalid format string
With %b I get the plot without any error:
Additionally, I'd like to remove the first and last tick labels to avoid the repetition.
I wonder if you know any workaround for my problem.
In python a string is converted to upper case via str.upper(). You may apply this via a matplotlib.ticker.FuncFormatter to the labels produced via the DateFormatter
fmt= lambda x,pos: mdates.DateFormatter('%b')(x,pos).upper()
ax.xaxis.set_major_formatter(ticker.FuncFormatter(fmt))
Complete example:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as ticker
x = pd.date_range("2001-01-01", "2001-12-31", freq="5D")
y = np.random.rand(len(x))
fig, ax=plt.subplots()
ax.plot(x,y)
ax.xaxis.set_major_locator(mdates.MonthLocator())
fmt= lambda x,pos: mdates.DateFormatter('%b')(x,pos).upper()
ax.xaxis.set_major_formatter(ticker.FuncFormatter(fmt))
plt.show()
Related
I have time-series plots (over 1 year) where the months on the x-axis are of the form Jan, Feb, Mar, etc, but I would like to have just the first letter of the month instead (J,F,M, etc). I set the tick marks using
ax.xaxis.set_major_locator(MonthLocator())
ax.xaxis.set_minor_locator(MonthLocator())
ax.xaxis.set_major_formatter(matplotlib.ticker.NullFormatter())
ax.xaxis.set_minor_formatter(matplotlib.dates.DateFormatter('%b'))
Any help would be appreciated.
The following snippet based on the official example here works for me.
This uses a function based index formatter order to only return the first letter of the month as requested.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.cbook as cbook
import matplotlib.ticker as ticker
datafile = cbook.get_sample_data('aapl.csv', asfileobj=False)
print 'loading', datafile
r = mlab.csv2rec(datafile)
r.sort()
r = r[-365:] # get the last year
# next we'll write a custom formatter
N = len(r)
ind = np.arange(N) # the evenly spaced plot indices
def format_date(x, pos=None):
thisind = np.clip(int(x+0.5), 0, N-1)
return r.date[thisind].strftime('%b')[0]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ind, r.adj_close, 'o-')
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
fig.autofmt_xdate()
plt.show()
I tried to make the solution suggested by #Appleman1234 work, but since I, myself, wanted to create a solution that I could save in an external configuration script and import in other programs, I found it inconvenient that the formatter had to have variables defined outside of the formatter function itself.
I did not solve this but I just wanted to share my slightly shorter solution here so that you and maybe others can take it or leave it.
It turned out to be a little tricky to get the labels in the first place, since you need to draw the axes, before the tick labels are set. Otherwise you just get empty strings, when you use Text.get_text().
You may want to get rid of the agrument minor=True which was specific to my case.
# ...
# Manipulate tick labels
plt.draw()
ax.set_xticklabels(
[t.get_text()[0] for t in ax.get_xticklabels(minor=True)], minor=True
)
I hope it helps:)
The original answer uses the index of the dates. This is not necessary. One can instead get the month names from the DateFormatter('%b') and use a FuncFormatter to use only the first letter of the month.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
from matplotlib.dates import MonthLocator, DateFormatter
x = np.arange("2019-01-01", "2019-12-31", dtype=np.datetime64)
y = np.random.rand(len(x))
fig, ax = plt.subplots()
ax.plot(x,y)
month_fmt = DateFormatter('%b')
def m_fmt(x, pos=None):
return month_fmt(x)[0]
ax.xaxis.set_major_locator(MonthLocator())
ax.xaxis.set_major_formatter(FuncFormatter(m_fmt))
plt.show()
I am looking to edit the formatting of the dates on the x-axis. The picture below shows how they appear on my bar graph by default. I would like to remove the repetition of 'Dec' and '2012' and just have the actual date numbers along the x-axis.
Any suggestions as to how I can do this?
In short:
import matplotlib.dates as mdates
myFmt = mdates.DateFormatter('%d')
ax.xaxis.set_major_formatter(myFmt)
Many examples on the matplotlib website. The one I most commonly use is here
While the answer given by Paul H shows the essential part, it is not a complete example. On the other hand the matplotlib example seems rather complicated and does not show how to use days.
So for everyone in need here is a full working example:
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter
myDates = [datetime(2012,1,i+3) for i in range(10)]
myValues = [5,6,4,3,7,8,1,2,5,4]
fig, ax = plt.subplots()
ax.plot(myDates,myValues)
myFmt = DateFormatter("%d")
ax.xaxis.set_major_formatter(myFmt)
## Rotate date labels automatically
fig.autofmt_xdate()
plt.show()
From the package matplotlib.dates as shown in this example the date format can be applied to the axis label and ticks for plot.
Below I have given an example for labeling axis ticks for multiplots
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
df = pd.read_csv('US_temp.csv')
plt.plot(df['Date'],df_f['MINT'],label='Min Temp.')
plt.plot(df['Date'],df_f['MAXT'],label='Max Temp.')
plt.legend()
####### Use the below functions #######
dtFmt = mdates.DateFormatter('%b') # define the formatting
plt.gca().xaxis.set_major_formatter(dtFmt) # apply the format to the desired axis
plt.show()
As simple as that
This wokrs prfectly for me
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,
AutoMinorLocator)
import matplotlib.dates as mdates
dtFmt = mdates.DateFormatter('%Y-%b') # define the formatting
plt.gca().xaxis.set_major_formatter(dtFmt)
# show every 12th tick on x axes
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1))
plt.xticks(rotation=90, fontweight='light', fontsize='x-small',)
I have an existing plot that was created with pandas like this:
df['myvar'].plot(kind='bar')
The y axis is format as float and I want to change the y axis to percentages. All of the solutions I found use ax.xyz syntax and I can only place code below the line above that creates the plot (I cannot add ax=ax to the line above.)
How can I format the y axis as percentages without changing the line above?
Here is the solution I found but requires that I redefine the plot:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mtick
data = [8,12,15,17,18,18.5]
perc = np.linspace(0,100,len(data))
fig = plt.figure(1, (7,4))
ax = fig.add_subplot(1,1,1)
ax.plot(perc, data)
fmt = '%.0f%%' # Format you want the ticks, e.g. '40%'
xticks = mtick.FormatStrFormatter(fmt)
ax.xaxis.set_major_formatter(xticks)
plt.show()
Link to the above solution: Pyplot: using percentage on x axis
This is a few months late, but I have created PR#6251 with matplotlib to add a new PercentFormatter class. With this class you just need one line to reformat your axis (two if you count the import of matplotlib.ticker):
import ...
import matplotlib.ticker as mtick
ax = df['myvar'].plot(kind='bar')
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
PercentFormatter() accepts three arguments, xmax, decimals, symbol. xmax allows you to set the value that corresponds to 100% on the axis. This is nice if you have data from 0.0 to 1.0 and you want to display it from 0% to 100%. Just do PercentFormatter(1.0).
The other two parameters allow you to set the number of digits after the decimal point and the symbol. They default to None and '%', respectively. decimals=None will automatically set the number of decimal points based on how much of the axes you are showing.
Update
PercentFormatter was introduced into Matplotlib proper in version 2.1.0.
pandas dataframe plot will return the ax for you, And then you can start to manipulate the axes whatever you want.
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(100,5))
# you get ax from here
ax = df.plot()
type(ax) # matplotlib.axes._subplots.AxesSubplot
# manipulate
vals = ax.get_yticks()
ax.set_yticklabels(['{:,.2%}'.format(x) for x in vals])
Jianxun's solution did the job for me but broke the y value indicator at the bottom left of the window.
I ended up using FuncFormatterinstead (and also stripped the uneccessary trailing zeroes as suggested here):
import pandas as pd
import numpy as np
from matplotlib.ticker import FuncFormatter
df = pd.DataFrame(np.random.randn(100,5))
ax = df.plot()
ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: '{:.0%}'.format(y)))
Generally speaking I'd recommend using FuncFormatter for label formatting: it's reliable, and versatile.
For those who are looking for the quick one-liner:
plt.gca().set_yticklabels([f'{x:.0%}' for x in plt.gca().get_yticks()])
this assumes
import: from matplotlib import pyplot as plt
Python >=3.6 for f-String formatting. For older versions, replace f'{x:.0%}' with '{:.0%}'.format(x)
I'm late to the game but I just realize this: ax can be replaced with plt.gca() for those who are not using axes and just subplots.
Echoing #Mad Physicist answer, using the package PercentFormatter it would be:
import matplotlib.ticker as mtick
plt.gca().yaxis.set_major_formatter(mtick.PercentFormatter(1))
#if you already have ticks in the 0 to 1 range. Otherwise see their answer
I propose an alternative method using seaborn
Working code:
import pandas as pd
import seaborn as sns
data=np.random.rand(10,2)*100
df = pd.DataFrame(data, columns=['A', 'B'])
ax= sns.lineplot(data=df, markers= True)
ax.set(xlabel='xlabel', ylabel='ylabel', title='title')
#changing ylables ticks
y_value=['{:,.2f}'.format(x) + '%' for x in ax.get_yticks()]
ax.set_yticklabels(y_value)
You can do this in one line without importing anything:
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter('{}%'.format))
If you want integer percentages, you can do:
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter('{:.0f}%'.format))
You can use either ax.yaxis or plt.gca().yaxis. FuncFormatter is still part of matplotlib.ticker, but you can also do plt.FuncFormatter as a shortcut.
Based on the answer of #erwanp, you can use the formatted string literals of Python 3,
x = '2'
percentage = f'{x}%' # 2%
inside the FuncFormatter() and combined with a lambda expression.
All wrapped:
ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y}%'))
Another one line solution if the yticks are between 0 and 1:
plt.yticks(plt.yticks()[0], ['{:,.0%}'.format(x) for x in plt.yticks()[0]])
add a line of code
ax.yaxis.set_major_formatter(ticker.PercentFormatter())
I am looking to edit the formatting of the dates on the x-axis. The picture below shows how they appear on my bar graph by default. I would like to remove the repetition of 'Dec' and '2012' and just have the actual date numbers along the x-axis.
Any suggestions as to how I can do this?
In short:
import matplotlib.dates as mdates
myFmt = mdates.DateFormatter('%d')
ax.xaxis.set_major_formatter(myFmt)
Many examples on the matplotlib website. The one I most commonly use is here
While the answer given by Paul H shows the essential part, it is not a complete example. On the other hand the matplotlib example seems rather complicated and does not show how to use days.
So for everyone in need here is a full working example:
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter
myDates = [datetime(2012,1,i+3) for i in range(10)]
myValues = [5,6,4,3,7,8,1,2,5,4]
fig, ax = plt.subplots()
ax.plot(myDates,myValues)
myFmt = DateFormatter("%d")
ax.xaxis.set_major_formatter(myFmt)
## Rotate date labels automatically
fig.autofmt_xdate()
plt.show()
From the package matplotlib.dates as shown in this example the date format can be applied to the axis label and ticks for plot.
Below I have given an example for labeling axis ticks for multiplots
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
df = pd.read_csv('US_temp.csv')
plt.plot(df['Date'],df_f['MINT'],label='Min Temp.')
plt.plot(df['Date'],df_f['MAXT'],label='Max Temp.')
plt.legend()
####### Use the below functions #######
dtFmt = mdates.DateFormatter('%b') # define the formatting
plt.gca().xaxis.set_major_formatter(dtFmt) # apply the format to the desired axis
plt.show()
As simple as that
This wokrs prfectly for me
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,
AutoMinorLocator)
import matplotlib.dates as mdates
dtFmt = mdates.DateFormatter('%Y-%b') # define the formatting
plt.gca().xaxis.set_major_formatter(dtFmt)
# show every 12th tick on x axes
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1))
plt.xticks(rotation=90, fontweight='light', fontsize='x-small',)
My data looks as follows:
2012021305, 65217
2012021306, 82418
2012021307, 71316
2012021308, 66833
2012021309, 69406
2012021310, 76422
2012021311, 94188
2012021312, 111817
2012021313, 127002
2012021314, 141099
2012021315, 147830
2012021316, 136330
2012021317, 122252
2012021318, 118619
2012021319, 115763
2012021320, 121393
2012021321, 130022
2012021322, 137658
2012021323, 139363
Where the first column is the data YYYYMMDDHH . I'm trying to graph the data using the csv2rec module. I can get the data to graph but the x axis and labels are not showing up the way that I expect them to.
import matplotlib
matplotlib.use('Agg')
from matplotlib.mlab import csv2rec
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from pylab import *
output_image_name='plot1.png'
input_filename="data.log"
input = open(input_filename, 'r')
input.close()
data = csv2rec(input_filename, names=['time', 'count'])
rcParams['figure.figsize'] = 10, 5
rcParams['font.size'] = 8
fig = plt.figure()
plt.plot(data['time'], data['count'])
ax = fig.add_subplot(111)
ax.plot(data['time'], data['count'])
hours = mdates.HourLocator()
fmt = mdates.DateFormatter('%Y%M%D%H')
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(fmt)
ax.grid()
plt.ylabel("Count")
plt.title("Count Log Per Hour")
fig.autofmt_xdate(bottom=0.2, rotation=90, ha='left')
plt.savefig(output_image_name)
I assume this has something to do with the date format. Any suggestions?
You need to convert the x-values to datetime objects
Something like:
time_vec = [datetime.strp(str(x),'%Y%m%d%H') for x in data['time']]
plot(time_vec,data['count'])
Currently, you are telling python to format integers (2012021305) as a date, which it does not know how to do, so it returns and empty string (although, I suspect that you are getting errors raised someplace).
You should also check your format string mark up.