What is subplot_adjust() doing to pyplot axes? - python-2.7

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()

Related

How to represent the data in x and y axis using matplotlib

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()

Animating Steronets

I have been looking around and have got to nowhere with this. I am trying to animate the poles on a stereonet diagram. However, the poles do not appear at the location that they should be in.
Figure 1 is the animated pole plot while Figure 2 is how the plot should be. I was wondering if anyone had an idea on how to proceed with this?
import matplotlib as mpl
mpl.use("TkAgg")
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
import mplstereonet
fig, ax = mplstereonet.subplots()
fig2, ax1 = mplstereonet.subplots()
ax.grid(True)
ax1.grid(True)
# Assume a strike and dip with a random variance.
# Current values should plot the poles at either 0, 180
strike, dip = 90, 80
num = 10
strikes = strike + 10 * np.random.randn(num)
dips = dip + 10 * np.random.randn(num)
poles, = ax.pole([], [], 'o')
def init():
poles.set_data([], [])
return poles,
def animate(i):
poles.set_data(strikes[:i], dips[:i])
return poles,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames = len(strikes), interval = 100, blit=True, repeat=False)
poles1 = ax1.pole(strikes, dips, 'o') # This is how the final image should look like
plt.show()

Iterate Pandas Series to create a new chart legend

After grouping etc. I get a Series like in the example below. I would like to show the average numbers for each bar. The code below shows only one entry (of course, as I have only one "legend"). Could anyone one suggest a smart way of showing these numbers?
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')
import pandas
# create Series
dict_ = {"Business" : 104.04,"Economy":67.04, "Markets":58.56, "Companies":38.48}
s = pandas.Series(data=dict_)
# plot it
ax = s.plot(kind='bar', color='#43C6DB', stacked=True, figsize=(20, 10), legend=False)
plt.tick_params(axis='both', which='major', labelsize=14)
plt.xticks(rotation=30) #rotate labels
# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
#create new legend
legend = ['%s (%.1f a day)' %(i, row/7) for i, row in s.iteritems()]
# Put the legend to the right of the current axis
L = ax.legend(legend, loc='center left', bbox_to_anchor=(1, 0.5), fontsize=18)
plt.show()
The legend only has a single entry. This is a handle of a blue bar. Therefore even if you set the labels to a longer list, only the first element of that list is used as label for the existing handle.
The idea can be to duplicate the legend handle to have the same size as the labels
legend = ['%s (%.1f a day)' %(i, row/7) for i, row in s.iteritems()]
h,l = ax.get_legend_handles_labels()
L = ax.legend(handles = h*len(legend), labels=legend, loc='center left',
bbox_to_anchor=(1, 0.5), fontsize=18)

AttributeError: draw_artist can only be used after an initial draw which caches the render

My requirement is to plot the data in polar graph. However I need to keep polar graph in particular angle to looks like "V" shape and data need to plotted in between the particular angle.
In python I don't find a solution to keep the polar graph in particular angle, Example : Graph should be display in between -60 to 60 degree radius. To achieve that I have looked into couple of existing examples and creating required polar graph with FloatingSubplot functions. However I am hitting the issue , when we try to use along with function animation function with blit=True. Error message is displayed is "AttributeError: draw_artist can only be used after an initial draw which caches the render"
Here is my code.
#
import matplotlib
matplotlib.use('Qt4Agg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib.animation as animation
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.transforms import Affine2D
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist import angle_helper
from mpl_toolkits.axisartist.grid_finder import MaxNLocator, DictFormatter
from mpl_toolkits.axisartist.floating_axes import GridHelperCurveLinear, FloatingSubplot
plt.close('all')
fig = plt.figure('Practice', dpi=100) # To set the fig title as pratice
ax1 = fig.add_subplot(2, 2, 1) # subplot for 1st plot
plt.ion()
ax1.grid(True)
def fractional_polar_axes(f, thlim=(0, 120), rlim=(0, 20), step=(30, 0.25),
thlabel='theta', rlabel='r', ticklabels=True, theta_offset=0, rlabels=None):
'''Return polar axes that adhere to desired theta (in deg) and r limits. steps for theta
and r are really just hints for the locators.'''
th0, th1 = thlim # deg
r0, r1 = rlim
thstep, rstep = step
tr_rotate = Affine2D().translate(theta_offset, 0)
# scale degrees to radians:
tr_scale = Affine2D().scale(np.pi / 180., 1.)
# pa = axes(polar="true") # Create a polar axis
pa = PolarAxes
tr = tr_rotate + tr_scale + pa.PolarTransform()
theta_grid_locator = angle_helper.LocatorDMS((th1 - th0) // thstep)
r_grid_locator = MaxNLocator((r1 - r0) // rstep)
theta_tick_formatter = angle_helper.FormatterDMS()
if rlabels:
rlabels = DictFormatter(rlabels)
grid_helper = GridHelperCurveLinear(tr,
extremes=(th0, th1, r0, r1),
grid_locator1=theta_grid_locator,
grid_locator2=r_grid_locator,
tick_formatter1=theta_tick_formatter,
tick_formatter2=rlabels)
a = FloatingSubplot(f, 222, grid_helper=grid_helper)
# a = Subplot(f,753, grid_helper=grid_helper)
# f.add_subplot(7,5,(3,34))
f.add_subplot(a)
# adjust x axis (theta):
print(a)
a.axis["bottom"].set_visible(False)
a.axis["top"].set_axis_direction("bottom") # tick direction
a.axis["top"].toggle(ticklabels=ticklabels, label=bool(thlabel))
a.axis["top"].major_ticklabels.set_axis_direction("top")
a.axis["top"].label.set_axis_direction("top")
a.axis["top"].major_ticklabels.set_pad(10)
# adjust y axis (r):
a.axis["left"].set_axis_direction("bottom") # tick direction
a.axis["right"].set_axis_direction("top") # tick direction
a.axis["left"].toggle(ticklabels=True, label=bool(rlabel))
# add labels:
a.axis["top"].label.set_text(thlabel)
a.axis["left"].label.set_text(rlabel)
# create a parasite axes whose transData is theta, r:
auxa = a.get_aux_axes(tr)
print(auxa)
# make aux_ax to have a clip path as in a?:
auxa.patch = a.patch
# this has a side effect that the patch is drawn twice, and possibly over some other
# artists. So, we decrease the zorder a bit to prevent this:
a.patch.zorder = -2
# add sector lines for both dimensions:
thticks = grid_helper.grid_info['lon_info'][0]
rticks = grid_helper.grid_info['lat_info'][0]
print(grid_helper.grid_info['lat_info'])
for th in thticks[1:-1]: # all but the first and last
auxa.plot([th, th], [r0, r1], ':', c='grey', zorder=-1, lw=0.5)
for ri, r in enumerate(rticks):
# plot first r line as axes border in solid black only if it isn't at r=0
if ri == 0 and r != 0:
ls, lw, color = 'solid', 1, 'black'
else:
ls, lw, color = 'dashed', 0.5, 'grey'
# From http://stackoverflow.com/a/19828753/2020363
auxa.add_artist(plt.Circle([0, 0], radius=r, ls=ls, lw=lw, color=color, fill=False,
transform=auxa.transData._b, zorder=-1))
return auxa
def animate(i):
global loopcount, th, r
th = th+.1
r = r+.1
datapoints.set_offsets(np.vstack((th,r)).T)
#print("in animate")
return datapoints,
if __name__ == '__main__':
r_locs = [0,5,10, 15, 20]
r_labels = ['0', '5', '10', '15', '20']
r_ticks = {loc: label for loc, label in zip(r_locs, r_labels)}
a1 = fractional_polar_axes(fig, thlim=(-60, 60), step=(20, 5),
theta_offset=90, rlabels=r_ticks)
th= 20
r=10
a1.scatter(th,r , c = 'r', alpha = 0.5, linewidths = '.2', s = 20) # plotting the line at thetha 20 and radius 10
datapoints = a1.scatter([], [], c='b', alpha = 0.5, linewidths = '.2', s = 20) # creating scatter line with given instruction,
ani = animation.FuncAnimation(fig, animate, frames=30, interval=20, blit=True)
plt.show(block=True)
#
"""
Above code is working perfectly fine with blit=False and also same solution working fine with line and scatter plotting in normal graph.
Please someone help me to resolve the issue.
"""

python, xlrd: Maniplulate spreadsheet data with xlrd function then graph the manipulated data

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.