Here in my program i want to create the month wise dates on x axis label and and another rs data i want to represent on the y axis.can you please help me how to mention my data in matplotlib.
Given below is my sample program:
import matplotlib.pyplot as plt
from matplotlib import style
# line 1 points
x1 = [1,2,3]
y1 = [2,4,1]
# plotting the line 1 points
plt.plot(x1, y1, 'g', label = "line 1",linewidth=10)
plt.title('Two lines on same graph!')
plt.xlabel('x - axis')
plt.ylabel('y - axis')
plt.legend()
plt.grid(True,color="k")
plt.show()
# xticks(np.arange(12), calendar.month_name[1:13], rotation=20)
i don't want to mention in between the values it is tacking the x and y values i want to mention like in given diagram.
After few edits and your comments. Is this more closer what you are looking for?
import matplotlib.pyplot as plt
import datetime
# line 1 points
val = [1,2,3,2,6]
cust = [2,4,1,6,2]
orders = [3,5,2,7,3]
col = [1,3,4,2,6]
# plotting the line 1 points
fig, ax = plt.subplots()
start_date = datetime.datetime(2019, 07, 01)
dates = []
# Dates based on the measurement count
# See: https://stackoverflow.com/questions/1060279/iterating-through-a-range-of-dates-in-python
for single_date in (start_date + datetime.timedelta(n) for n in range(len(val))):
dates.append(single_date.strftime('%Y-%m-%d'))
# Values
plt.plot(dates, val, '.',color='g', markersize=12)
plt.plot(dates, val, label='Values', color='g')
# Customers
plt.plot(dates, cust, '.',color='b', markersize=12)
plt.plot(dates, cust, label='Customers',color='b')
# Orders
plt.plot(dates, orders, '.',color='r', markersize=12)
plt.plot(dates, orders, label='Orders',color='r')
# Collection
plt.plot(dates, col, '.',color='black', markersize=12)
plt.plot(dates, col, label='Collection',color='black')
plt.title('Four lines on same graph!')
plt.tick_params(axis='x', rotation=20)
plt.xlabel('x - axis')
plt.ylabel('y - axis')
plt.grid(True,color="k")
plt.legend()
plt.show()
Related
Hi I ploted two lines in a figure, the x-axis is the datetime from '2016-04-01' to '2017-03-31', the value showed on the grid line width is one month, namely 30 days, but I want to the grid line of width is 50 days. I mean that I want to show the date value of x-axis is: 2016-04-01, 2016-05-21,2016-07-10,2016-10-18,2016-12-07,2017-01-26,2017-03-17.
T
My code is following:
import seaborn as sn
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
sn.set_style("darkgrid")
xfmt = mdates.DateFormatter('%Y-%m-%d')
fig = plt.figure(figsize=(15,4))
ax = fig.add_subplot(111)
ax.xaxis.set_major_formatter(xfmt)
lst_predictions = list(predictions2)
len_predictions = len(lst_predictions)
plt.plot(lst_index, list(test_y2), label = 'actual')
plt.ylim(ymin=0)
plt.ylim(ymax=140)
plt.xlim([lst_index[0], lst_index[-1]])
plt.plot(lst_index, lst_predictions, label='pred')
plt.legend(loc="upper left")
plt.grid(True)
You can use a DayLocator to control the location of the ticks.
xloc = mdates.DayLocator(interval=50)
ax.xaxis.set_major_locator(xloc)
Usually you would use it in cases where you want to mark the 1st and 15th of each month or so. Since 50 days is more than a month, the location cannot be determined in terms of a month. You may still use the interval argument to space the ticks 50 days appart. However the starting point will be rather arbitrary.
Complete code:
import datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
start_date = datetime.date(2016, 04, 01)
end_date = datetime.date(2017, 07, 01)
date_list = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]
values = np.cumsum(np.random.rand(len(date_list))-.5)+20
fig, ax = plt.subplots(figsize=(15,4))
ax.plot(date_list, values, label = 'actual')
xloc = mdates.DayLocator(interval=50)
ax.xaxis.set_major_locator(xloc)
xfmt = mdates.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_formatter(xfmt)
plt.legend(loc="upper left")
plt.grid(True)
plt.show()
I am trying to plot a graph. It has a list contains action name (text) and another list which contains action's frequency (int).
I want to plot a connected graph. This is the code I've written:
xTicks=np.array(action)
x=np.array(count)
y=np.array(freq)
pl.xticks(x,xTicks)
pl.xticks(rotation=90)
pl.plot(x,y)
pl.show()
In the list xTicks, I have actions and in the list y, I have their frequencies .
With the above code, I am getting this graph:
Why am I getting extra spaces on x axis? It should be symmetric and the size of lists are 130-135 so how can I scroll it?
You need to set x to an evenly spaced list in order to get your x ticks to be evenly spaced. The following is an example with some made up data:
import matplotlib.pyplot as plt
import numpy as np
action = ["test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9"]
freq = [5,3,7,4,8,3,5,1,12]
y=np.array(freq)
xTicks=np.array(action)
x = np.arange(0,len(action),1) # evenly spaced list with the same length as "freq"
plt.plot(x,y)
plt.xticks(x, xTicks, rotation=90)
plt.show()
This produces the following plot:
Update:
A simple example of a slider is shown below. You will have to make changes to this in order to get it exactly how you want but it will be a start:
from matplotlib.widgets import Slider
freq = [5,3,7,4,8,3,5,1,12,5,3,7,4,8,3,5,1,12,5,3,7,4,8,3,5,1,12,4,9,1]
y=np.array(freq)
x = np.arange(0,len(freq),1) # evenly spaced list with the same length as "action"
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
l, = plt.plot(x, y, lw=2, color='red')
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor="lightblue")
sfreq = Slider(axfreq, 'Slider', 0.1, 10, valinit=3)
def update(val):
l.set_xdata(val* x)
fig.canvas.draw_idle()
sfreq.on_changed(update)
plt.show()
This produces the following graph which has a slider:
I am trying to extract data from an excel spreadsheet, then find a percent change between adjacent rows. The columns that I would like to do this manipulation on is column 1 and 4. I would like to then graph these percent changes in two different bar charts using subplots using column 0 as the x axis.
I am able to do everything except extract the data and formulate a percent change between adjacent rows. The formula for the percent change is Current/previous-1 or (r,0)/(r-1,0)-1. Below is my current script:
import xlrd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tkr
import matplotlib.dates as mdates
import datetime
from matplotlib import rc
rc('mathtext', default='regular')
file_location = "/Users/adampatel/Desktop/psw01.xls"
workbook = xlrd.open_workbook(file_location, on_demand = False)
worksheet = workbook.sheet_by_name('Data 1')
x = [worksheet.cell_value(i+1699, 0) for i in range(worksheet.nrows-1699)]
y1 = [worksheet.cell_value(i+1699, 1) for i in range(worksheet.nrows-1699)]
y2 = [worksheet.cell_value(i+1699, 4) for i in range(worksheet.nrows-1699)]
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212, sharex = ax1)
start_date = datetime.date(1899, 12, 30)
dates=[start_date + datetime.timedelta(xval) for xval in x]
ax1.xaxis.set_major_locator(mdates.MonthLocator((), bymonthday=1, interval=2))
ax1.xaxis.set_minor_locator(mdates.MonthLocator((), bymonthday=1, interval=1))
ax1.xaxis.set_major_formatter(mdates.DateFormatter("%b'%y"))
ly1 = ax1.bar(dates, y1, 0.9)
ly2 = ax2.bar(dates, y2, 0.9)
ax1.grid()
ax2.grid()
ax1.set_ylim(-3,3)
ax2.set_ylim(-3,3)
fig.text(0.5, 0.04, 'Inventory Weekly Percent Change', ha='center', va='center', size = '14')
fig.text(0.06, 0.5, 'Weekly Percent Change', ha='center', va='center', size = '14', rotation='vertical')
ax1.set_title('Oil', size = '12')
ax2.set_title('Gasoline', size = '12')
plt.savefig('Gasoline Inventories Weekly Percent Change.png', bbox_inches='tight', dpi=300)
plt.show()
Given list of values:
y1 = [1000,1010,950,1050,1100,1030]
Pure python solution:
Use the zip function to create tuples of the numerator and denominator. Then use list comprehension to get a list of the percent changes.
pct_chg = [1.0*num / den - 1 for num, den in zip(y1[1:], y1)]
Numpy solution:
Convert list to numpy array, then perform computation using array slices.
a1 = np.array(y1)
pct_chg = np.divide(a1[1:],a1[:-1])-1
Pandas package solution:
Convert list to Pandas series and use the built-in percent change function
s1 = pd.Series(y1)
pct_chg = s1.pct_change()
Now, pct_chg is a series too. You can get its values in a numpy array via pct_chg.values. Matplotlib should accept numpy arrays as containers in most cases.
I am trying to plot several subplots in a pyplot figure, one of which has two subplots. I handle this by creating one extra pyplot.ax based on the location of the bottom one.
Now, a problem arise when I adjust axes 1 through 4 using fig.subplots_adjust(), in order to leave an extra space on the right for legend. On the picture below, you can see that although my two datasets are the same length, the bar plot stretches further to the right.
I would like to apply the same adjustment to ax5 as I do to the other four axes when using fig.subplot_adjust(), but I cannot figure out what this method is doing with the
matplotlib.axes.Axes instance.
Looking at the documentation, I could not find a method that suits my purpose:
http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes
So what is fig.subplot_adjust() doing to my axes? How can I reproduce this behavior so that ALL axes align?
import numpy as np
import matplotlib.pyplot as plt
import datetime
fig, ( ax1, ax2, ax3 , ax4) = plt.subplots( figsize=(18.0, 11.0) , nrows=4, ncols=1)
## some fake stand-alone data
days = 365 * 5
dates = [datetime.datetime(2000, 1, 1, 0, 0) + datetime.timedelta( day - 1) for day in range(days)]
data_series = np.random.rand( days )
data_series2 = [np.sin(x * 2 * np.pi / 365 ) + np.random.rand(1) * 0.1 for x in range( days ) ]
###### Plots made up temperatures
ax4.set_frame_on(False)
ax4.plot_date( dates , data_series2 , color="black", ls="solid", lw=2, ms=0 )
# Now on the same plot try to add som precipitation as a plot
ax5 = fig.add_axes(ax4.get_position() , frameon=True, zorder = -10.0)
ax5.bar( dates, data_series, edgecolor="blue", zorder = -10.0 )
ax5.xaxis_date()
# gets rid of bar-plot labels
ax5.set_xticks([]); ax5.set_yticks([])
fig.subplots_adjust(right=0.8) # <- Pandora's box
plt.show()
The problem here is that ax5 is not in a subplot.
fig.get_axes()
[<matplotlib.axes._subplots.AxesSubplot at 0x220175c0>,
<matplotlib.axes._subplots.AxesSubplot at 0x18d48240>,
<matplotlib.axes._subplots.AxesSubplot at 0x1c5f3630>,
<matplotlib.axes._subplots.AxesSubplot at 0x1a430710>,
<matplotlib.axes._axes.Axes at 0x1c4defd0>] # There is ax5 and it is not under _subplots
so when you do
fig.subplots_adjust(right=0.8)
you adjust the subplot and not the axe directly so you don't affect ax5.
An easy way to correct than is to adjust ax4 before calling ax5, so ax5 will have the same proportion than ax4.
By calling
fig.subplots_adjust(right=0.8)
before
ax5 = fig.add_axes(ax4.get_position() , frameon=True, zorder = -10.0)
you will get the proper output.
So your code just have to look like that;
import numpy as np
import matplotlib.pyplot as plt
import datetime
fig, ( ax1, ax2, ax3 , ax4) = plt.subplots( figsize=(18.0, 11.0) , nrows=4, ncols=1)
## some fake stand-alone data
days = 365 * 5
dates = [datetime.datetime(2000, 1, 1, 0, 0) + datetime.timedelta( day - 1) for day in range(days)]
data_series = np.random.rand( days )
data_series2 = [np.sin(x * 2 * np.pi / 365 ) + np.random.rand(1) * 0.1 for x in range( days ) ]
###### Plots made up temperatures
ax4.set_frame_on(False)
ax4.plot_date( dates , data_series2 , color="black", ls="solid", lw=2, ms=0 )
# I move the subplot_adjust here before you create ax5
fig.subplots_adjust(right=0.8)
# Now on the same plot try to add som precipitation as a plot
ax5 = fig.add_axes(ax4.get_position() , frameon=True, zorder = -10.0)
ax5.bar( dates, data_series, edgecolor="blue", zorder = -10.0 )
ax5.xaxis_date()
# gets rid of bar-plot labels
ax5.set_xticks([]); ax5.set_yticks([])
plt.show()
In a scatter plot matrix, I would like to draw a region in every subplot and print the points that are included in the region. I found the LassoSelector widget, which does exactly that. I am trying to extend its functionality for more than one subplots. I am getting the following error: self.xys = collection.get_offsets(),
AttributeError: 'numpy.flatiter' object has no attribute 'get_offsets'.
when the line selector = SelectFromCollection(axes, ax.flat) is in the for loop, and I am getting the error: self.canvas = ax.figure.canvas,AttributeError: 'numpy.ndarray' object has no attribute 'figure' when the line selector = SelectFromCollection(ax, ax.flat) is outside of the loop. Why does this happen?
Here is my code:
from __future__ import print_function
import numpy as np
from matplotlib.widgets import LassoSelector
from matplotlib.path import Path
class SelectFromCollection(object):
"""Select indices from a matplotlib collection using `LassoSelector`.
Selected indices are saved in the `ind` attribute. This tool highlights
selected points by fading them out (i.e., reducing their alpha values).
If your collection has alpha < 1, this tool will permanently alter them.
Note that this tool selects collection objects based on their *origins*
(i.e., `offsets`).
Parameters
----------
ax : :class:`~matplotlib.axes.Axes`
Axes to interact with.
collection : :class:`matplotlib.collections.Collection` subclass
Collection you want to select from.
alpha_other : 0 <= float <= 1
To highlight a selection, this tool sets all selected points to an
alpha value of 1 and non-selected points to `alpha_other`.
"""
def __init__(self, ax, collection, alpha_other=0.3):
self.canvas = ax.figure.canvas
self.collection = collection
self.alpha_other = alpha_other
self.xys = collection.get_offsets()
self.Npts = len(self.xys)
# Ensure that we have separate colors for each object
self.fc = collection.get_facecolors()
if len(self.fc) == 0:
raise ValueError('Collection must have a facecolor')
elif len(self.fc) == 1:
self.fc = np.tile(self.fc, self.Npts).reshape(self.Npts, -1)
self.lasso = LassoSelector(ax, onselect=self.onselect)
self.ind = []
def onselect(self, verts):
path = Path(verts)
self.ind = np.nonzero([path.contains_point(xy) for xy in self.xys])[0]
self.fc[:, -1] = self.alpha_other
self.fc[self.ind, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
print(selector.xys[selector.ind])
#selector.disconnect()
def disconnect(self):
self.lasso.disconnect_events()
self.fc[:, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
if __name__ == '__main__':
import matplotlib.pyplot as plt
plt.ion()
data=np.loadtxt(r"data.txt")
x = data[:, 3]
x1 = data[:, 4]
y = data[:,5]
y1 = data[:,6]
fig, ax = plt.subplots(nrows=2, ncols=2, squeeze=True)
for axes, marker in zip(ax.flat, ['o', 'o']):
ax.flat[0].plot(x, y, 'r', ls='', marker=marker)
ax.flat[1].plot(x, x1,'r', ls='', marker=marker)
ax.flat[2].plot(x, y1,'r', ls='', marker=marker)
ax.flat[3].plot(y, x1,'r', ls='', marker=marker)
selector = SelectFromCollection(ax, ax.flat)
plt.show(block=True)
plt.draw()
Ok, I found a few problems that are causing your code not to work properly. There we go:
Firts of all, you modified the SelectFromCollection class that you got from the LassoSelector example to print every selected point, but forgot a detail:
class SelectFromCollection(object):
def __init__(self, ax, collection, alpha_other=0.3):
# ...
# No changes here...
# ...
def onselect(self, verts):
path = Path(verts)
self.ind = np.nonzero([path.contains_point(xy) for xy in self.xys])[0]
self.fc[:, -1] = self.alpha_other
self.fc[self.ind, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
print(self.xys[self.ind]) # <- THIS LINE HAS CHANGED!!!
#selector.disconnect()
def disconnect(self):
# ...
# No changes here...
# ...
Now you can use multiple instances of SelectFromCollection.
Then, you are also creating only one instance of SelectFromCollection (so only one subplot would react). Furthermore, according to the doctsring the second argument the __init__ method expects is a matplotlib.collections.Collection instance.
Instead you are passing it a numpy array (in fact a numpy.Flatiter) that contains two Axes instances. If you look at the example, there it gets a Collection instance returned by the scattercommand (they use scatter instead of plot).
All in all, and restiling the loop, this is my version
if __name__ == '__main__':
import matplotlib.pyplot as plt
data=np.random.rand(3,100)
xdata = data[:-1] # all rows but last
y = data[-1] # last row
fig, axes = plt.subplots(nrows=1, ncols=2, squeeze=True)
markers = ['o','^']
selectors =[]
for i in xrange(xdata.shape[0]):
pts = axes[i].scatter(xdata[i], y, c='r', marker=markers[i])
selectors.append(SelectFromCollection(axes[i], pts))
plt.show()
EDIT
If you want to do more plots, it is not hard. You can try to write more synthetic code with a for loop and so on, but an easier solution is to write directly the repetitions of the code:
if __name__ == '__main__':
import matplotlib.pyplot as plt
data=np.loadtxt(r"data.txt")
x = data[:, 3]
x1 = data[:, 4]
y = data[:,5]
y1 = data[:,6]
fig, axes = plt.subplots(nrows=2, ncols=2)
pts1 = axes[0,0].scatter(x, y, c='r', marker='o')
select1 = SelectFromCollection(axes[0,0], pts1)
pts2 = axes[1,0].scatter(x, x1, c='r', marker='o')
select2 = SelectFromCollection(axes[1,0], pts2)
pts3 = axes[0,1].scatter(x, y1, c='r', marker='o')
select3 = SelectFromCollection(axes[0,1], pts3)
pts4 = axes[1,1].scatter(y, x1, c='r', marker='o')
select4 = SelectFromCollection(axes[1,1], pts4)
plt.show()
Still, it is necessary that you change the definition of the SelectFromCollection class as I said above.