I'm trying to fill the area under the curve where the y-value is 1. The x-axis is a datetime array with non-regular values. As you can see the fill also includes areas where there is no x-data. Is there a way to tell fill_between to only fill "between" valid data? i.e. in the plot below I'd like the areas between "missing" samples to be white
tx = array(datetimes) # Array of irregular datetimes
ty = array([ones and zeros]) # Array of ones and zeros same size as tx
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(tx, ty, 'r.')
ax.fill_between(tx, 0, 1, where(ty==1))
This might be what you're aiming for.
If it is then you can use rectangular patches. In this code:
y is the list of values meant to correspond to your 'irregular' pattern.
delta_float measures the horizontal distance in the graph corresponding to delta, the distance between ticks.
Notice that the patches are positioned and sized based on dates and delta_float units respectively.
import datetime
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.dates import DayLocator, HourLocator, DateFormatter, drange, date2num
from numpy import arange
date1 = datetime.datetime(2000, 3, 2)
date2 = datetime.datetime(2000, 3, 6)
delta = datetime.timedelta(hours=6)
dates = drange(date1, date2, delta)
delta_float = (dates[-1]-dates[0])/len(dates)
y = [1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,0]
fig, ax = plt.subplots()
ax.plot_date(dates, y, 'r.')
ax.add_patch(patches.Rectangle((dates[0], 0), delta_float, 1, color='grey'))
ax.add_patch(patches.Rectangle((dates[4], 0), 2*delta_float, 1, color='grey'))
ax.add_patch(patches.Rectangle((dates[8], 0), delta_float, 1, color='grey'))
ax.add_patch(patches.Rectangle((dates[12], 0), delta_float, 1, color='grey'))
ax.xaxis.set_major_locator(DayLocator())
ax.xaxis.set_minor_locator(HourLocator(arange(0, 25, 6)))
ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
ax.fmt_xdata = DateFormatter('%Y-%m-%d %H:%M:%S')
fig.autofmt_xdate()
plt.show()
Related
Dear People of the Internet
I have calculated a frequency distribution and I would now like to plot it in a certain manner. So far I have calculated and plotted the frequency distribution, but I couldn't find a solution for the endproduct I am looking for. My code with an example dataset for now is:
import matplotlib.pyplot as plt
from scipy import stats
import numpy as np
import pandas as pd
# example data
rng = np.random.RandomState(seed=12345)
a1 = stats.norm.rvs(size=1000, random_state=rng)
res = stats.relfreq(a1, numbins=34)
x = res.lowerlimit + np.linspace(0, res.binsize*res.frequency.size, res.frequency.size)
# plotting
fig = plt.figure(figsize=(6, 3))
ax = fig.add_subplot(1, 1, 1)
ax.bar(x, res.frequency, width=res.binsize)
ax.set_title('Frequency Distribution of 1D Vix Returns')
ax.set_xlim([x.min(), x.max()])
ax.set_xticks(ax.get_xticks()[::1])
plt.show()
As a last step, I would like to plot the x-Axis just as in the attached picture. Instead of single number I would like to have the interval. I couldn't find a source in which this matter is resolved. Has anyone encountered the same problem or knows any source which has a solution to it? Thanks in advance
Have a look at this nice answer:
https://stackoverflow.com/a/6353051/10372616.
I added the code to your current plot.
import matplotlib.pyplot as plt
from scipy import stats # ????
import numpy as np
import pandas as pd # ????
# example data
rng = np.random.RandomState(seed=12345)
a1 = stats.norm.rvs(size=1000, random_state=rng)
res = stats.relfreq(a1, numbins=34)
x = res.lowerlimit + np.linspace(0, res.binsize*res.frequency.size, res.frequency.size)
# plotting
fig = plt.figure(figsize=(6, 3))
ax = fig.add_subplot(1, 1, 1)
ax.bar(x, res.frequency, width=res.binsize)
ax.set_title('Frequency Distribution of 1D Vix Returns')
ax.set_xlim([x.min(), x.max()])
ax.set_xticks(ax.get_xticks()[::1])
# Change traditional tick labels to range labels
# ----------------------------------------------------------------
ax.set_xticklabels([]) # hide your previous x tick labels
bins = ax.get_xticks()[::1]
bin_centers = 0.5 * np.diff(bins) + bins[:-1]
for a, b, x in zip(bins, bins[1:], bin_centers):
label = '{:0.0f} to {:0.0f}'.format(a, b)
ax.annotate(label, xy=(x, 0), xycoords=('data', 'axes fraction'),
xytext=(0, -10), textcoords='offset points', va='top', ha='center', rotation=90)
plt.show()
Before:
After:
I have a graph with dates on the x axis and a scalar on the y axis.
when I do this:
plt.plot_date([date_from, date_to], [0, 10000], fmt='-', color='r')
it works as expected (although I'm not sure what the fmt='-' part does and would be happy to learn about it)
but, having a lot of line segments, when I do this:
import matplotlib.dates as mpd
lines = [[(mpd.date2num(date_from), 0), (mpd.date2num(date_to), 10000)]]
c = np.array([(1, 0, 0, 1)])
lc = mc.LineCollection(lines, colors=c, linewidths=2)
ax.add_collection(lc)
nothing is appearing; why is that?
i want to make graph using matplotlib in python.
np.load(name.npy')
i searched many things and i tried
for example..just...
x = [dt.datetime(2003, 05, 01), dt.datetime(2008, 06, 01)]
df = np.load(r'file')
y = df
Replace the end date on the date-range to your desired graph, and the 'y' should be array loaded
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
start_date = '2003-05-01'
y = np.load(r'c:\python27\abnormal.npy')
x = pd.date_range(start=start_date, periods=len(y), freq='D')
plt.plot(x,y,'.')
plt.show()
If your input array does not contain ordered pairs such as [(0,1), (1,1), (2,2)] and only contains one set of numbers '[1, 2, 3, 4]`, you neeed to create a set of x-coordinates. For a time series in days, you could try something like this:
import datetime
import numpy as np
import matplotlib.pyplot as plt
def getData(fileName):
# Load the data file to serve as y-axis coordinates
y = np.load(fileName)
# For each y coordinate we need an x coordinate
time_offset = list(range(len(y)))
# Convert time_offset to a time-series
# We will assume x-values equal number of days since a beginDate
x = []
beginDate = datetime.date(2015, 6, 1) # The date to begin our time series
for n in time_offset:
date = beginDate + datetime.timedelta(n) # Date + number_of_Days_passed
x.append(date)
return x, y
def plot(x, y):
# Plot the data
fig = plt.figure()
ax = plt.subplot2grid((1,1), (0,0), rowspan=1, colspan=1)
ax.scatter(x, y)
for label in ax.xaxis.get_ticklabels():
label.set_rotation(90)
ax.grid(True)
plt.subplots_adjust(left=.10, bottom=.19, right=.93, top=.95, wspace=.20, hspace=0)
plt.show()
x, y = getData('abnormal.npy')
plot(x, y)
I have coded the following program with matplotlib to graph no.of elements with time.
import pylab
import numpy as np
import datetime
from matplotlib.dates import YearLocator, MonthLocator, DateFormatter
date1 = datetime.date(1995, 1, 1)
date2 = datetime.date(2004, 4, 12)
years = YearLocator() # every year
months = MonthLocator() # every month
yearsFmt = DateFormatter('%Y')
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
ax.autoscale_view()
pylab.ylim(0, 250)
plt.yticks(np.linspace(0,250,6,endpoint=True))
pylab.xlabel('YEAR')
pylab.ylabel('No. of sunspots')
pylab.title('SUNSPOT VS YEAR GRAPH')
a=[[50,50],[100,100],[250, 250],[200,200],[150,150]]
plt.plot(*zip(*a), marker='o', color='r', ls='')
The output is as follows
However,I was expecting it to display years instead of numbers in x-axis.
You are plotting years, but the years are 50, 100, 250, 200, and 150. These are the first element in the lists inside of a, which is passed to pyplot.plot as the x values.
You want to define your dates somewhere, though you'll also probably want to set the xticks to be the same as the dates you're plotting, as I can tell you care about the graph looking neat.
import pylab
import numpy as np
import datetime
from matplotlib.dates import YearLocator, MonthLocator, DateFormatter
Also, don't forget to import pyplot
import matplotlib.pyplot as plt
Here are some example dates. You can change them to whatever exact date you have for the sunspot measurements.
a=[[datetime.date(1995, 1, 1), 50],
[datetime.date(2000, 1, 1), 100],
[datetime.date(2005, 1, 1), 250],
[datetime.date(2010, 1, 1), 200],
[datetime.date(2015, 1, 1), 150]
]
years = YearLocator() # every year
months = MonthLocator() # every month
yearsFmt = DateFormatter('%Y')
Call gca to get current axis before you modify the axis.
ax = plt.gca()
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
ax.autoscale_view()
pylab.ylim(0, 250)
plt.yticks(np.linspace(0,250,6,endpoint=True))
Pick out the dates from the a array to use them as xtick labels.
dates = [date for date,sunspot in a]
plt.xticks(dates)
pylab.xlabel('YEAR')
pylab.ylabel('No. of sunspots')
pylab.title('SUNSPOT VS YEAR GRAPH')
plt.plot(*zip(*a), marker='o', color='r', ls='')
plt.show()
I'm trying to plot a graph of dates on the x-axis and values on the y-axis. It works fine, except that I can't get the range of the x-axis to be appropriate. The x-axis range is always Jan 2012 to Jan 2016, despite my dates being from today. I am even specifying that xlim should be the first and last date.
I'm writing this for python-django, if that's relevant.
import datetime
import matplotlib.pyplot as plt
x = [datetime.date(2014, 1, 29), datetime.date(2014, 1, 29), datetime.date(2014, 1, 29)]
y = [2, 4, 1]
fig, ax = plt.subplots()
ax.plot_date(x, y)
ax.set_xlim([x[0], x[-1]])
canvas = FigureCanvas(plt.figure(1))
response = HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
And here is the output:
Edit:
Having seen actual data from the OP, all of the values are at the same date/time. So matplotlib is automatically zooming the x-axis out. You can still manually set the x-axis limits with datetime objects
If I do something like this on matplotlib v1.3.1:
import datetime
import matplotlib.pyplot as plt
x = [datetime.date(2014, 1, 29)] * 3
y = [2, 4, 1]
fig, ax = plt.subplots()
ax.plot_date(x, y, markerfacecolor='CornflowerBlue', markeredgecolor='white')
fig.autofmt_xdate()
ax.set_xlim([datetime.date(2014, 1, 26), datetime.date(2014, 2, 1)])
ax.set_ylim([0, 5])
I get:
And the axes limits match the dates that I specified.
With help from Paul H's solution, I was able to change the range of my time-based x-axis.
Here is a more general solution for other beginners.
import matplotlib.pyplot as plt
import datetime as dt
# Set X range. Using left and right variables makes it easy to change the range.
#
left = dt.date(2020, 3, 15)
right = dt.date(2020, 7, 15)
# Create scatter plot of Positive Cases
#
plt.scatter(
x, y, c="blue", edgecolor="black",
linewidths=1, marker = "o", alpha = 0.8, label="Total Positive Tested"
)
# Format the date into months & days
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
# Change the tick interval
plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=30))
# Puts x-axis labels on an angle
plt.gca().xaxis.set_tick_params(rotation = 30)
# Changes x-axis range
plt.gca().set_xbound(left, right)
plt.show()