I would like to plot a graph with the below sample, X-axis: 'Time', Y-axis: 'Celcius'. With the attached code, I got [09:00:00.000000 09:05:00.000000 ... 09:30:00.000000] at the x-axis, instead of [2013-01-02 09:00 2013-01-02 09:05 ... 2013-01-02 09:30].
Does anyone know what the correct way to format x-axis to the designated format is?
data = {'Celcius': [36.906441135554658, 51.286294403017202], 'Time': [datetime.datetime(2013, 1, 2, 9, 0), datetime.datetime(2013, 1, 2, 9, 30)]}
def plotTemperature(self, data):
logging.debug(data)
t = data.get('Time')
T = data.get('Celcius')
years = mdates.YearLocator() # every year
months = mdates.MonthLocator() # every month
days = mdates.DayLocator() # every day
hours = mdates.HourLocator() # every hour
minutes = mdates.MinuteLocator() # every minute
yearsFmt = mdates.DateFormatter('%Y')
hoursFmt = mdates.DateFormatter('%H')
fig, ax = plt.subplots()
ax.plot(t, T)
# format the ticks
# ax.xaxis.set_major_locator(hours)
# ax.xaxis.set_major_formatter(hoursFmt)
# ax.xaxis.set_minor_locator(minutes)
datemin = datetime.datetime(min(t).year, min(t).month, min(t).day, min(t).hour, min(t).minute)
datemax = datetime.datetime(max(t).year, max(t).month, max(t).day, max(t).hour, max(t).minute)
ax.set_xlim(datemin, datemax)
# format the coords message box
def temperature(x): return '$%1.2f'%x
ax.format_xdata = mdates.DateFormatter('%Y-%m-%d %H:%M')
ax.format_ydata = temperature
ax.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
plt.show()
Add this:
import dateutil
import matplotlib.dates as mdates
ymdhFmt = mdates.DateFormatter('%Y-%m-%d %H:%M')
rule = mdates.rrulewrapper(dateutil.rrule.MINUTELY, interval=30)
loc = mdates.RRuleLocator(rule)
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(ymdhFmt)
This answer was posted as an edit to the question matplotlib Plot X-axis with '%Y-%m-%d %H:%M' by the OP twfx under CC BY-SA 3.0.
Related
I am trying to convert values to axis units. I checked codes with similar problems but none addressed this specific challenge. As can be seen in the image below, expected plot (A) was supposed to show month (Jan, Feb etc.) on the x-axis, but it was showing dates (2015-01 etc) in plot (B).
Below is the source code, kindly assist. Thanks.
plt.rcParams["font.size"] = 18
plt.figure(figsize=(20,5))
plt.plot(df.air_temperature,label="Air temperature at Frankfurt Int. Airport in 2015")
plt.xlim(("2015-01-01","2015-12-31"))
plt.xticks(["2015-{:02d}-15".format(x) for x in range(1,13,1)],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"])
plt.legend()
plt.ylabel("Temperature (°C)")
plt.show()
A wise way to draw the plot with datetime is to use datetime format in place of str; so, first of all, you should do this conversion:
df = pd.read_csv(r'data/frankfurt_weather.csv')
df['time'] = pd.to_datetime(df['time'], format = '%Y-%m-%d %H:%M')
Then you can set up the plot as you please, preferably following Object Oriented Interface:
plt.rcParams['font.size'] = 18
fig, ax = plt.subplots(figsize = (20,5))
ax.plot(df['time'], df['air_temperature'], label = 'Air temperature at Frankfurt Int. Airport in 2015')
ax.legend()
ax.set_ylabel('Temperature (°C)')
plt.show()
Then you can customize:
x ticks' labels format and position with matplotlib.dates:
ax.xaxis.set_major_locator(md.MonthLocator(interval = 1))
ax.xaxis.set_major_formatter(md.DateFormatter('%b'))
x axis limits:
ax.set_xlim([pd.to_datetime('2015-01-01', format = '%Y-%m-%d'),
pd.to_datetime('2015-12-31', format = '%Y-%m-%d')])
capital first letter of x ticks' labels for months' names
fig.canvas.draw()
ax.set_xticklabels([month.get_text().title() for month in ax.get_xticklabels()])
Complete Code
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as md
df = pd.read_csv(r'data/frankfurt_weather.csv')
df['time'] = pd.to_datetime(df['time'], format = '%Y-%m-%d %H:%M')
plt.rcParams['font.size'] = 18
fig, ax = plt.subplots(figsize = (20,5))
ax.plot(df['time'], df['air_temperature'], label = 'Air temperature at Frankfurt Int. Airport in 2015')
ax.legend()
ax.set_ylabel('Temperature (°C)')
ax.xaxis.set_major_locator(md.MonthLocator(interval = 1))
ax.xaxis.set_major_formatter(md.DateFormatter('%b'))
ax.set_xlim([pd.to_datetime('2015-01-01', format = '%Y-%m-%d'),
pd.to_datetime('2015-12-31', format = '%Y-%m-%d')])
fig.canvas.draw()
ax.set_xticklabels([month.get_text().title() for month in ax.get_xticklabels()])
plt.show()
I am graphing three lines on a single plot. I want the x-axis to display the date the data was taken on and the time from 00:00 to 24:00. Right now my code displays the time of day correctly but for the date, instead of the date that the data was recorded on being displayed, the current date is shown (12-18). I am unsure how to correct this. Also it would be acceptable for my plot to show only time from 00:00 to 24:00 with out the date on the x-axis. Thank you for your help!!
# set index as time for graphing
monAverages['Time'] = monAverages['Time'].apply(lambda x: pd.to_datetime(str(x)))
index = monAverages['Time']
index = index.apply(lambda x: pd.to_datetime(str(x)))
averagePlot = dfSingleDay
predictPlot = predictPlot[np.isfinite(predictPlot)]
datasetPlot = datasetPlot[np.isfinite(datasetPlot)]
predictPlot1 = pd.DataFrame(predictPlot)
datasetPlot1 = pd.DataFrame(datasetPlot)
averagePlot.set_index(index, drop=True,inplace=True)
datasetPlot1.set_index(index, drop=True,inplace=True)
predictPlot1.set_index(index, drop=True,inplace=True)
plt.rcParams["figure.figsize"] = (10,10)
plt.plot(datasetPlot1,'b', label='Real Data')
plt.plot(averagePlot, 'y', label='Average for this day of the week')
plt.plot(predictPlot1, 'g', label='Predictions')
plt.title('Power Consumption')
plt.xlabel('Date (00-00) and Time of Day(00)')
plt.ylabel('kW')
plt.legend()
plt.show()
You need to be sure that you get only the time:
import matplotlib.dates as mdates
# set index as time for graphing
monAverages['Time'] = monAverages['Time'].apply(lambda x: pd.to_datetime(str(x)))
index = monAverages['Time']
#index = index.apply(lambda x: pd.to_datetime(str(x)))
dates= [dt.datetime.strptime(d,'%Y-%m-%d %H:%M:%S').time() for d in index]
averagePlot = dfSingleDay
predictPlot = predictPlot[np.isfinite(predictPlot)]
datasetPlot = datasetPlot[np.isfinite(datasetPlot)]
predictPlot1 = pd.DataFrame(predictPlot)
datasetPlot1 = pd.DataFrame(datasetPlot)
plt.rcParams["figure.figsize"] = (10,10)
plt.plot(dates,datasetPlot1,'b', label='Real Data')
plt.plot(dates,averagePlot, 'y', label='Average for this day of the week')
plt.plot(dates,predictPlot1, 'g', label='Predictions')
plt.title('Power Consumption')
plt.xlabel('Date (00-00) and Time of Day(00)')
plt.ylabel('kW')
plt.legend()
plt.show()
This code here explains how you can run it
import datetime as dt
import matplotlib.pyplot as plt
dates = ['2019-12-18 00:00:00','2019-12-18 12:00:00','2019-12-18 13:00:00']
x = [dt.datetime.strptime(d,'%Y-%m-%d %H:%M:%S').time() for d in dates]
y = range(len(x))
plt.plot(x,y)
plt.gcf().autofmt_xdate()
plt.show()
I have plots of climate time series for daily mean temperature, precipitation and global radiation.
I generated plots like this:
https://i.ibb.co/w4x2FMN/temp-mean-1999-2018.png
On x-axis I just generated list of the numbers 1 - 365 which represent the day of year (DOY).
What I actually want is, that the x-axis is devided in month names (as strings) like this:
https://i.ibb.co/cL2zc87/rplot.jpg
I tried already a lot of different things but nothing worked.
fig = plt.figure(figsize=(10,10))
ax = plt.axes()
x = np.arange(1,366) # here I define the List with DOY
ax.fill_between(x, temp_cum['min'], temp_cum['max'], color='lightgray', label='1999-2017')
#ax.plot(x, merge_table_99_17_without, color='grey', linewidth=0.3)
ax.plot(x, temp_cum['2018'], color='black', label='2018');
ax.legend(loc='upper left')
ax.set_ylabel('daily mean temperature [°C]')
#ax.set_xlabel('DOY')
plt.show()
First you should convert your numbers to date objects as described in this post. You can use the following function.
import datetime
def serial_date_to_string(srl_no):
new_date = datetime.datetime(2018,1,1,0,0) + datetime.timedelta(srl_no - 1)
return new_date.strftime("%Y-%m-%d")
Then you have to format your x-axis to only show the month and not the full dates. This post describes how to do this in detail.
Thank you very much #AUBSieGUL.
Your second link finally helped me:
import numpy as np
import matplotlib.pyplot as plt
import datetime
import matplotlib.dates as mdates
fig = plt.figure(figsize=(12,12))
ax = plt.axes()
### I added this!
# Set the locator
locator = mdates.MonthLocator() # every month
# Specify the format - %b gives us Jan, Feb...
fmt = mdates.DateFormatter('%b')
numdays = 365
base = datetime.datetime(2018, 1, 1, 0, 0, 0, 0)
date_list = [base + datetime.timedelta(days=x) for x in range(0,numdays)]
###
###replaced all x with date_list
ax.fill_between(date_list, prec_cum['min'], prec_cum['max'], color='lightgray', label='1999-2017')
ax.plot(date_list, merge_table_99_17_cumsum_without, color='grey', linewidth=0.3)
ax.plot(date_list, prec_cum['2018'], color='black', label='2018');
ax.legend(loc='upper left')
ax.set_ylabel('cum. sums of global radiation [kW/m²]')
#ax.set_xlabel('DOY')
### I added this!
X = plt.gca().xaxis
X.set_major_locator(locator)
# Specify formatter
X.set_major_formatter(fmt)
###
plt.show()
I want to draw a plot in matplotlib that shows the temperature of August in 2016 and 2017. x-axis is time and y-axis is temparature. I try to stack 2 plots (one for 2016, one for 2017) on top of each other by sharing the x-axis that ranges from 2016-08-01 00:00:00 to 2016-08-31 23:00:00 and showing only the day of the month.
import matplotlib.dates as mdates
myFmt = mdates.DateFormatter('%d')
# times series from 2016-08-01 00:00:00 to 2016-08-31 23:00:00
x = stats_august_2016.MESS_DATUM
# temperature in 08.2016
y1 = stats_august_2016.TT_TU
# temperature in 08.2017
y2 = stats_august_2017.TT_TU
f, ax = plt.subplots()
# plot temp in 08.2016
ax.plot(x, y1, 'yellow', label = '2016')
# plot temp in 08.2017
ax.plot(x, y2, 'red', label = '2017')
# format x-axis to show only days of the month
ax.xaxis.set_major_formatter(myFmt)
ax.grid(True)
plt.rcParams["figure.figsize"] = (12, 8)
plt.xlabel("Day of the Month", fontsize = 20, color = 'Blue')
plt.xticks(fontsize = 15)
plt.ylabel("Temperature ($\degree$C)", fontsize = 20, color = 'Blue')
plt.yticks(fontsize = 15)
ax.set_ylim(5, 35)
plt.title("Temperature in August 2016 and 2017", fontsize = 30, color = 'DarkBlue')
plt.legend(prop = {'size': 20}, frameon = True, fancybox = True, shadow = True, framealpha = 1, bbox_to_anchor=(1.22, 1))
plt.show()
Everything looks fine except the last tick of x-axis is somehow 2016-09-01 00:00:00. And the result looks odd with the 1 at the end.
How can I fix this?
The problem is, that your data is ranging until to some time late at the 31st of August of each year
# times series from 2016-08-01 00:00:00 to 2016-08-31 23:00:00
Matplotlib is then autoscaling the axis reaching up to the first day of the next month, displayed as a 1 in your chosen format. If you want to avoid this, you can set the x limit of the axis to the last timestamp of your data
ax.set_xlim([x[0], x[-1]])
The whitespace margin left and right of your axis will disappear then, though. If you want to keep this margin and still want to avoid the ticklabel of 1st of september, you can hide the last x-tick label with
xticks = ax.xaxis.get_major_ticks()
xticks[-1].label1.set_visible(False)
try:
ax.set_xlim(right=pd.Timestamp("2016-08-30 00:00:00"))
This will set the limit to day 30th.
I'm not managing to plot matplotlib.finance.candlestick without the weekends (blank spaces between every 5 candlesticks). The example from Matplotlib's website doesn't exclude weekends either and the way to exclude weekends on other plots doesn't seem to apply to CandleSticks.
Has anybody come across this before?
ps. as requested, here is the example:
#!/usr/bin/env python
from pylab import *
from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
DayLocator, MONDAY
from matplotlib.finance import quotes_historical_yahoo, candlestick,\
plot_day_summary, candlestick2
# (Year, month, day) tuples suffice as args for quotes_historical_yahoo
date1 = ( 2004, 2, 1)
date2 = ( 2004, 4, 12 )
mondays = WeekdayLocator(MONDAY) # major ticks on the mondays
alldays = DayLocator() # minor ticks on the days
weekFormatter = DateFormatter('%b %d') # Eg, Jan 12
dayFormatter = DateFormatter('%d') # Eg, 12
quotes = quotes_historical_yahoo('INTC', date1, date2)
fig = figure()
fig.subplots_adjust(bottom=0.2)
ax = fig.add_subplot(111)
ax.xaxis.set_major_locator(mondays)
ax.xaxis.set_minor_locator(alldays)
ax.xaxis.set_major_formatter(weekFormatter)
#plot_day_summary(ax, quotes, ticksize=3)
candlestick(ax, quotes, width=0.6)
ax.xaxis_date()
ax.autoscale_view()
setp( gca().get_xticklabels(), rotation=45, horizontalalignment='right')
show()
After your 'quotes' line:
weekday_quotes = [tuple([i]+list(quote[1:])) for i,quote in enumerate(quotes)]
then
candlestick(ax, weekday_quotes, width=0.6)
This will plot the data without the gaps between weekdays, now you have to change the xticks back to dates, preferably mondays. Assuming your first quote was a monday:
import matplotlib.dates as mdates
ax.set_xticks(range(0,len(weekday_quotes),5))
ax.set_xticklabels([mdates.num2date(quotes[index][0]).strftime('%b-%d') for index in ax.get_xticks()])
This is pretty gross but seems to get the job done - good luck!
While #JMJR's answer works, I find this to be more robust:
def plot(x):
plt.figure()
plt.title("VIX curve")
def idx(val=[0]):
val[0] = val[0] + 1
return val[0]
d = collections.defaultdict(idx)
# give each date an index
[d[t] for t in sorted(x.index.get_level_values('baropen_datetime').unique())]
# use the index
x['idx'] = [d[t] for t in x.index.get_level_values('baropen_datetime')]
# plot using index
x.groupby('code').apply(lambda y: plt.plot(y.idx.values,
y.close.values,
label=y.index.get_level_values('code')[0]))
plt.legend()
plt.show()
plt.close()