Reputation: 371
I have a graph that was plotted using datetime objects for the x axis and I want to be able to color beneath the graph itself (the y-values) and the x axis. I found this post Matplotlib's fill_between doesnt work with plot_date, any alternatives? describing a similar problem, but the proposed solutions didn't help me at all.
My code:
import matplotlib.patches as mpatches
import matplotlib.dates
import matplotlib.pyplot as plt
import numpy as np
import csv
from tkinter import *
from datetime import datetime
from tkinter import ttk
columns="YEAR,MONTH,DAY,HOUR,PREC,PET,Q,UZTWC,UZFWC,LZTWC,LZFPC,LZFSC,ADIMC,AET"
data_file="FFANA_000.csv"
UZTWC = np.genfromtxt(data_file,
delimiter=',',
names=columns,
skip_header=1,
usecols=("UZTWC"))
list_of_datetimes = []
skipped_header = False;
with open(data_file, 'rt') as f:
reader = csv.reader(f, delimiter=',', quoting=csv.QUOTE_NONE)
for row in reader:
if skipped_header:
date_string = "%s/%s/%s %s" % (row[0].strip(), row[1].strip(), row[2].strip(), row[3].strip())
dt = datetime.strptime(date_string, "%Y/%m/%d %H")
list_of_datetimes.append(dt)
skipped_header = True
dates = matplotlib.dates.date2num(list_of_datetimes)
fig = plt.figure(1)
#UZTWC
ax1 = fig.add_subplot(111)
plt.plot(dates, UZTWC, '-', color='b', lw=2)
ax1.fill_between(dates, 0, UZTWC)
fig.autofmt_xdate()
plt.title('UZTWC', fontsize=15)
plt.ylabel('MM', fontsize=10)
plt.tick_params(axis='both', which='major', labelsize=10)
plt.tick_params(axis='both', which='minor', labelsize=10)
plt.grid()
plt.show()
This yields:
Traceback (most recent call last):
File "test_color.py", line 36, in <module>
ax1.fill_between(dates, 0, UZTWC)
File "C:\Users\rbanks\AppData\Local\Programs\Python\Python35-32\lib\site-packages\matplotlib\__init__.py", line 1812, in inner
return func(ax, *args, **kwargs)
File "C:\Users\rbanks\AppData\Local\Programs\Python\Python35-32\lib\site-packages\matplotlib\axes\_axes.py", line 4608, in fill_between
y2 = ma.masked_invalid(self.convert_yunits(y2))
File "C:\Users\rbanks\AppData\Local\Programs\Python\Python35-32\lib\site-packages\numpy\ma\core.py", line 2300, in masked_invalid
condition = ~(np.isfinite(a))
TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
It seems the issue comes with fill_between not being able to handle my dates being of type 'numpy.ndarray'. Do I need to just convert this to another data type for this to work?
EDIT: After more testing, I've found that I still get this exact error even after trying to use list_of_datetimes, and after converting all of my datetimes to timestamps, so I'm starting to wonder if it is a type issue after all.
Sample data:
%YEAR,MO,DAY,HR,PREC(MM/DT),ET(MM/DT),Q(CMS), UZTWC(MM),UZFWC(MM),LZTWC(MM),LZFPC(MM),LZFSC(MM),ADIMC(MM), ET(MM/DT)
2012, 5, 1, 0, 0.000, 1.250, 0.003, 2.928, 0.000, 3.335, 4.806, 0.000, 6.669, 1.042
2012, 5, 1, 6, 0.000, 1.250, 0.003, 2.449, 0.000, 3.156, 4.798, 0.000, 6.312, 0.987
2012, 5, 1, 12, 0.000, 1.250, 0.003, 2.048, 0.000, 2.970, 4.789, 0.000, 5.940, 0.929
2012, 5, 1, 18, 0.000, 1.250, 0.003, 1.713, 0.000, 2.782, 4.781, 0.000, 5.564, 0.869
2012, 5, 2, 0, 0.000, 1.250, 0.003, 1.433, 0.000, 2.596, 4.772, 0.000, 5.192, 0.809
2012, 5, 2, 6, 0.000, 1.250, 0.003, 1.199, 0.000, 2.414, 4.764, 0.000, 4.829, 0.750
I am using Python 3.5.0 and matplotlib 1.5.1 on Windows 10 and I gained all of my dependencies through WinPython https://sourceforge.net/projects/winpython/
Upvotes: 2
Views: 448
Reputation: 169314
I've yet to determine what went wrong in your original code but I got it working with pandas:
import pandas as pd, matplotlib.pyplot as plt, matplotlib.dates as mdates
df = pd.read_csv('/path/to/yourfile.csv')
df['date'] = df['%YEAR'].astype(str)+'/'+df['MO'].astype(str)+'/'+df['DAY'].astype(str)
df['date'] = pd.to_datetime(df['date'])
dates = [date.to_pydatetime() for date in df['date']]
yyyy_mm_dd_format = mdates.DateFormatter('%Y-%m-%d')
plt.clf()
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot_date(dates,df[' UZTWC(MM)'],'-',color='b',lw=2)
ax.fill_between(dates,0,df[' UZTWC(MM)'])
ax.xaxis.set_major_formatter(yyyy_mm_dd_format)
ax.set_xlim(min(dates), max(dates))
fig.autofmt_xdate()
plt.show()
Upvotes: 2