I'm new to matplotlib, and trying to plot something quite difficult.
I would like to plot something like (taken from the matplotlib docs):
Except, I want the timeline (x-axis) and stems to have labels in time, like:
timeline = ['0:01:00', '0:02:00', '0:03:00', '0:04:00', ...]
stems1 = ['0:01:45', '0:03:55', '0:04:22', ...]
stems2 = ['0:02:21', '0:06:54', ...
Notes:
Timeline ticks are evenly spaced
stems1 and stems2 don't necesarily have the same number of points, but are in order (like a video timeline)
It would be even better if stems1 and stems2 were different colors.
If anyone could point me in the right direction, or even code a working example, it'd be greatly appreciated! Thank you for reading.
Edit:
Following #r-beginners's answer to this post
I have something like this:
for time, level, label, va in zip(timeline, levels, labels, verticalalignments):
ax.annotate(label, xy=(time, level), xytext=(15, np.sign(level)*15),
textcoords="offset points",
verticalalignment=va,
horizontalalignment="right",
color='blue')
for time, level, pred, va in zip(timeline, levels, preds, verticalalignments):
ax.annotate(pred, xy=(time, level), xytext=(15, np.sign(level)*15),
textcoords="offset points",
verticalalignment=va,
horizontalalignment="right",
color='green')
The issue is that the graphs are overlapping, stem color are both red, and the stems don't align with the timeline.
Edit 2:
With #r-beginners code, I've tried it with 2 new stems, where stem1 isn't being plotted completely:
stem1 = ['0:08:08', '0:08:52', '0:09:42', '0:10:20', '0:10:55', '0:11:24', '0:12:31', '0:13:07', '0:13:45', '0:14:16', '0:14:49', '0:15:20', '0:15:51', '0:16:21', '0:16:53', '0:17:28', '0:19:01', '0:19:22', '0:20:19', '0:20:48', '0:21:19', '0:22:05', '0:23:06', '0:23:34', '0:24:03', '0:24:30', '0:24:51', '0:25:18', '0:25:54', '0:26:25', '0:27:07', '0:28:05', '0:29:04', '0:29:30', '0:30:34', '0:32:57', '0:33:28', '0:33:57', '0:34:35', '0:35:01', '0:35:41', '0:36:06', '0:36:30', '0:37:01', '0:37:33', '0:38:06', '0:38:40', '0:39:21', '0:40:02', '0:40:22', '0:40:42', '0:41:32', '0:41:56', '0:43:20', '0:43:39', '0:44:02', '0:44:26', '0:45:04', '0:45:32', '0:46:02', '0:47:00', '0:47:42', '0:48:05', '0:48:35', '0:49:02', '0:49:25', '0:49:56', '0:50:43', '0:51:25', '0:51:43', '0:52:18', '0:52:49', '0:53:08']
stem2 = ['0:09:49', '0:10:24', '0:14:27', '0:24:31', '0:26:03']
Code afterwards:
# Create figure
fig, ax = plt.subplots(figsize=(100, 10), constrained_layout=True)
ax.set(title='TEST')
# Stem values
names = [e for row in zip(stem1, stem2) for e in row]
# Timeline
timeline = [datetime.datetime.strptime(n, '%H:%M:%S') for n in names]
# Stem levels
levels = np.tile([-5, 5, -3, 3, -1, 1], int(np.ceil(len(names)/6)))[:len(names)]
# Stems
ax.vlines(timeline, 0, levels, color='tab:red')
# Plot timeline
ax.plot(timeline, np.zeros_like(timeline), "-o", color="k", markerfacecolor="w")
# Plot GT labels and predictions
for time, level, name in zip(timeline, levels, names):
ax.annotate(name, xy=(time, level),
xytext=(15, np.sign(level)*3),
textcoords='offset points',
horizontalalignment='right',
verticalalignment='bottom' if level > 0 else 'top',
color='green' if level > 0 else 'blue')
# De-clutter axes
ax.yaxis.set_visible(False)
ax.spines[["left", "top", "right"]].set_visible(False)
# ...
minutes = mdates.MinuteLocator(interval=1)
minutes_fmt = mdates.DateFormatter('%M:%S')
ax.xaxis.set_major_locator(minutes)
ax.xaxis.set_major_formatter(minutes_fmt)
# Rotate x-ticks
plt.setp(ax.get_xticklabels(), rotation=30, ha="right")
# Save figure
plt.savefig('test.png', bbox_inches='tight')
The data was only partially available, so I created it appropriately. I have solved your problem by referring to the official example that you refer to. For overlapping strings, create a list of positive and negative placement heights and draw a vertical line in red. Convert the stem information to time series information and draw a timeline. In the annotation looping process, the placement height value is judged for placement and color to distinguish them. The time series representation of the x-axis is set by MinuteLocator to determine the time format.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import matplotlib.dates as mdates
from datetime import datetime
fig, ax = plt.subplots(figsize=(16, 4), constrained_layout=True)
ax.set(title="Time line demo ")
stem1 = ['0:08:08', '0:08:52', '0:09:42', '0:10:20', '0:10:55', '0:11:24', '0:12:31', '0:13:07', '0:13:45', '0:14:16', '0:14:49', '0:15:20', '0:15:51', '0:16:21', '0:16:53', '0:17:28', '0:19:01', '0:19:22', '0:20:19', '0:20:48', '0:21:19', '0:22:05', '0:23:06', '0:23:34', '0:24:03', '0:24:30', '0:24:51', '0:25:18', '0:25:54', '0:26:25', '0:27:07', '0:28:05', '0:29:04', '0:29:30', '0:30:34', '0:32:57', '0:33:28', '0:33:57', '0:34:35', '0:35:01', '0:35:41', '0:36:06', '0:36:30', '0:37:01', '0:37:33', '0:38:06', '0:38:40', '0:39:21', '0:40:02', '0:40:22', '0:40:42', '0:41:32', '0:41:56', '0:43:20', '0:43:39', '0:44:02', '0:44:26', '0:45:04', '0:45:32', '0:46:02', '0:47:00', '0:47:42', '0:48:05', '0:48:35', '0:49:02', '0:49:25', '0:49:56', '0:50:43', '0:51:25', '0:51:43', '0:52:18', '0:52:49', '0:53:08']
stem2 = ['0:09:49', '0:10:24', '0:14:27', '0:24:31', '0:26:03']
stems = stem1 + stem2
timelines = sorted([datetime.strptime(s, '%H:%M:%S') for s in stem])
labels = [datetime.strftime(t, '%H:%M:%S') for t in timelines]
levels = np.tile([-7, 7, -5, 5, -3, 3, -1, 1], int(np.ceil(len(timelines)/8)))[:len(timelines)]
ax.vlines(timelines, 0, levels, color='tab:red')
ax.plot(timelines, np.zeros_like(timelines), "-o", color="k", markerfacecolor="w")
for t, l, b in zip(timelines, levels, labels):
if datetime.strftime(t, '%H:%M:%S')[1:] in stem2:
color = 'blue'
else:
color = 'green'
ax.annotate(b, xy=(t, l),
xytext=(22, np.sign(l)*3), textcoords='offset points',
horizontalalignment='right',
verticalalignment='bottom' if l > 0 else 'top',
color=color
)
ax.yaxis.set_visible(False)
ax.spines[["left", "top", "right"]].set_visible(False)
ax.spines['bottom'].set_position(('data', -8))
minutes = mdates.MinuteLocator(interval=1)
minutes_fmt = mdates.DateFormatter('%M:%S')
ax.xaxis.set_major_locator(minutes)
ax.xaxis.set_major_formatter(minutes_fmt)
plt.setp(ax.get_xticklabels(), rotation=90, ha='center')
plt.show()
Related
I've got some code used to generate an event timeline, but I'd like to add in an additional line plot showing quantity sold on each day. But when I run the plot, the timeline gets compressed and the Y-axis expands to the new plot. The only way to get around this issue is to normalize the quantity plot values which seems to fit the y-axis limits of the timeline plot, but ideally I'd like to keep the original values from the line plot in the first picture and get it working with the timeline plot from the second picture, so it's the original values and centered/scaled properly. The data is just formatted as a text file like this: Date,Event \n 12 July 2021, Event 1
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
def GenerateTimeLine2(data, data02, title="Timeline", xaxis_format="%d %b", day_interval=5, figsize=(8, 5)):
levels = np.array([-5, 5, -3, 3, -1, 1])
fig, ax = plt.subplots(figsize=figsize)
# Create the base line
start = min(data.index)
stop = max(data.index)
ax.plot((start, stop), (0, 0), 'k', alpha=.5)
# Iterate through data annoting each one
for ii, (idate, iname) in enumerate(data.itertuples()):
level = levels[ii % 6]
vert = 'top' if level < 0 else 'bottom'
ax.scatter(idate, 0, s=100, facecolor='w', edgecolor='k', zorder=9999)
# Plot a line up to the text
ax.plot((idate, idate), (0, level), c='r', alpha=.7)
# Give the text a faint background and align it properly
ax.text(idate, level, iname,ha='right', va=vert, fontsize=14,
backgroundcolor=(1., 1., 1., .3))
ax.set(title=title)
# Set the xticks formatting
# format xaxis with days intervals
ax.get_xaxis().set_major_locator(mdates.DayLocator(interval=day_interval))
ax.get_xaxis().set_major_formatter(mdates.DateFormatter(xaxis_format))
fig.autofmt_xdate()
#add in overlay line plot
#ax.plot(data02)
#print(ax.axis())
#min_c = min(data02.values.tolist())
#max_c = max(data02.values.tolist())
#ax.set_ylabel(min_c,max_c)
norm = lambda x: 5*(x-x.min())/(x.max()-x.min())
ax.set_yticks(norm(data02.values))
#((data02.values-(min(data02.values.tolist())))/(max(data02.values.tolist())-min(data02.values.tolist()))))
ax.yaxis.tick_right()
ax.yaxis.set_major_locator(plt.MaxNLocator(5))
ax.axes.set_ylabel('Quanitity')
ax.yaxis.set_label_position("right")
ax.plot(norm(data02))
#ax.plot((min_c,max_c), (0, 0), 'k', alpha=.5)
#print(ax.yaxis)
# Remove components for a cleaner look
plt.setp((list(ax.spines.values())), visible=False)#ax.get_yticklabels() +
return ax
data = pd.read_csv(r'testdata01.txt', parse_dates=True, index_col=0)
data02 = pd.read_csv(r'rap_a.txt', parse_dates=True, index_col=0)
ax = GenerateTimeLine2(data,data02,title='Event Timeline',
day_interval=1,figsize=(8,5))
#ax.patch.set_facecolor('gray')
#ax.plot(data02)
plt.show()
I'm trying to make the same chart as below and wonder if matplotlib has a similar chart to make that.
The chart below is the result of the STM topic model in the R package
I have probs values using DMR in Python:
array([[0.07204196, 0.04238116],
[0.04518877, 0.30546978],
[0.0587892 , 0.19870868],
[0.16710107, 0.07182639],
[0.128209 , 0.02422131],
[0.15264449, 0.07237352],
[0.2250081 , 0.06986096],
[0.1337716 , 0.10750801],
[0.01197221, 0.06736039],
[0.00527367, 0.04028973]], dtype=float32)
These are the results and left is Negative words and right is Positive
Example of negative positive proportion chart:
It is possible to create something quite close to the image you included. I understood that the right column should be negative while the right column should be positive?
First make the data negative:
import numpy as np
arr = np.array([[0.07204196, 0.04238116],
[0.04518877, 0.30546978],
[0.0587892 , 0.19870868],
[0.16710107, 0.07182639],
[0.128209 , 0.02422131],
[0.15264449, 0.07237352],
[0.2250081 , 0.06986096],
[0.1337716 , 0.10750801],
[0.01197221, 0.06736039],
[0.00527367, 0.04028973]], dtype="float32")
# Make the right col negative
arr[:, 0] *= -1
Then we can plot like so:
from string import ascii_lowercase
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
for y, x in enumerate(arr.flatten()):
# Get a label from the alphabet
label = ascii_lowercase[y]
# Plot the point
ax.plot(x, y, "o", color="black")
# Annotate the point with the label
ax.annotate(label, xy=(x, y), xytext=(x - 0.036, y), verticalalignment="center")
# Add the vertical line at zero
ax.axvline(0, ls="--", color="black", lw=1.25)
# Make the x axis equal
xlim = abs(max(ax.get_xlim(), key=abs))
ax.set_xlim((-xlim, xlim))
# Remove y axis
ax.yaxis.set_visible(False)
# Add two text labels for the x axis
for text, x in zip(["Negative", "Positive"], ax.get_xlim()):
ax.text(x / 2, -3.75, f"{text} Reviews", horizontalalignment="center")
Which outputs:
You can tweak the values in the calls to ax.annotate and ax.text if you need to change the locations of the text on the plot or x-axis.
I'm not sure what the key part of the question is. That is, are you more interested in labeling the individual points based on the category, or if you're more concerned with the unique circle with a line through it. With the array provided it's a little confusing about what the data represents.
What I've assumed is each sublist represents a single category. With that in mind, what I did was make a separate column (delta) for the differences in values and then plotted them vs the index.
# New column (delta) with styling
df['delta'] = df[0]-df[1]
col = np.where(df.delta>0,'g',np.where(df.index<0,'b','r'))
fig, ax = plt.subplots(figsize =(10,7))
# Style it up a bit
plt.title('Differnece in Topic Proportion (Negative vs Positive)')
plt.xlabel('Net Review Score')
plt.ylabel('Index Number')
plt.tight_layout()
plt.savefig("Evolution of rapport of polarisation - (Aluminium).png")
plt.scatter(df['delta'], df.index, s=None, c=col, marker=None, linewidth=2)
plt.axvline(x = 0, color = 'b', label = 'axvline - full height', linestyle="--" )
That gives an out of this:
Currently seaborn offers functionality for split violinplots by setting split=True, according to a hue variable. I would like to make a 'half' violin plot, i.e. a plot where half of each violin is omitted. Such a plot depicts something similar to a pdf for each continuous variable, plotted on one side of each vertical line of each categorical variable only.
I have managed to trick seaborn to plot this with an extra data point outside the plotted range of values and an extra dummy hue, but I would like to know if this can be done without actually altering the dataset, e.g. within sns.violinplot() arguments.
For instance, this graph:
Was created by this snippet:
# imports
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# load dataset from seaborn
datalist = sns.get_dataset_names()
dataset_name = 'iris'
if dataset_name in datalist:
df = sns.load_dataset(dataset_name)
else:
print("Dataset with name: " + dataset_name + " was not found in the available datasets online by seaborn.")
# prepare data
df2 = df.append([-999,-999,-999,-999,'setosa'])
df2['huecol'] = 0.0
df2['huecol'].iloc[-1]= -999
# plot
fig = plt.figure(figsize=(6,6))
sns.violinplot(x='species',y="sepal_width",
split=True, hue ='huecol', inner = 'quartile',
palette="pastel", data=df2, legend=False)
plt.title('iris')
# remove hue legend
leg = plt.gca().legend()
leg.remove()
plt.ylim([1,5.0])
plt.show()
I was looking for a solution similar to this but did not find anything satisfactory. I ended up calling seaborn.kdeplot multiple times as violinplot is essentially a one-sided kernel density plot.
Example
Function definition for categorical_kde_plot below
categorical_kde_plot(
df,
variable="tip",
category="day",
category_order=["Thur", "Fri", "Sat", "Sun"],
horizontal=False,
)
with horizontal=True, the output would look like:
Code
import seaborn as sns
from matplotlib import pyplot as plt
def categorical_kde_plot(
df,
variable,
category,
category_order=None,
horizontal=False,
rug=True,
figsize=None,
):
"""Draw a categorical KDE plot
Parameters
----------
df: pd.DataFrame
The data to plot
variable: str
The column in the `df` to plot (continuous variable)
category: str
The column in the `df` to use for grouping (categorical variable)
horizontal: bool
If True, draw density plots horizontally. Otherwise, draw them
vertically.
rug: bool
If True, add also a sns.rugplot.
figsize: tuple or None
If None, use default figsize of (7, 1*len(categories))
If tuple, use that figsize. Given to plt.subplots as an argument.
"""
if category_order is None:
categories = list(df[category].unique())
else:
categories = category_order[:]
figsize = (7, 1.0 * len(categories))
fig, axes = plt.subplots(
nrows=len(categories) if horizontal else 1,
ncols=1 if horizontal else len(categories),
figsize=figsize[::-1] if not horizontal else figsize,
sharex=horizontal,
sharey=not horizontal,
)
for i, (cat, ax) in enumerate(zip(categories, axes)):
sns.kdeplot(
data=df[df[category] == cat],
x=variable if horizontal else None,
y=None if horizontal else variable,
# kde kwargs
bw_adjust=0.5,
clip_on=False,
fill=True,
alpha=1,
linewidth=1.5,
ax=ax,
color="lightslategray",
)
keep_variable_axis = (i == len(fig.axes) - 1) if horizontal else (i == 0)
if rug:
sns.rugplot(
data=df[df[category] == cat],
x=variable if horizontal else None,
y=None if horizontal else variable,
ax=ax,
color="black",
height=0.025 if keep_variable_axis else 0.04,
)
_format_axis(
ax,
cat,
horizontal,
keep_variable_axis=keep_variable_axis,
)
plt.tight_layout()
plt.show()
def _format_axis(ax, category, horizontal=False, keep_variable_axis=True):
# Remove the axis lines
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
if horizontal:
ax.set_ylabel(None)
lim = ax.get_ylim()
ax.set_yticks([(lim[0] + lim[1]) / 2])
ax.set_yticklabels([category])
if not keep_variable_axis:
ax.get_xaxis().set_visible(False)
ax.spines["bottom"].set_visible(False)
else:
ax.set_xlabel(None)
lim = ax.get_xlim()
ax.set_xticks([(lim[0] + lim[1]) / 2])
ax.set_xticklabels([category])
if not keep_variable_axis:
ax.get_yaxis().set_visible(False)
ax.spines["left"].set_visible(False)
if __name__ == "__main__":
df = sns.load_dataset("tips")
categorical_kde_plot(
df,
variable="tip",
category="day",
category_order=["Thur", "Fri", "Sat", "Sun"],
horizontal=True,
)
The answer is simply, no, it's not possible with seaborn without tricking it into thinking there is a hue present.
This answer shows how to do it in matplotlib and in principle the same can be applied to seaborn violinplots as well, namely to cut out half of the violin path.
It's not necessary to modify the data:
ax = sns.violinplot(
data=tips,
x="day", y="total_bill", hue=True,
hue_order=[True, False], split=True,
)
ax.legend_ = None
I would like to draw a rectangle to indicate a range within the x axis. I can use locators for setting ticks and labels, but I don't seem to succeed using them to draw the rectangle. How could I go about it?!
import datetime as DT
from matplotlib import pyplot as plt
import matplotlib.dates as dates
ddata = [DT.datetime.strptime('2010-02-05', "%Y-%m-%d"),
DT.datetime.strptime('2010-02-19', "%Y-%m-%d"),
DT.datetime.strptime('2010-03-05', "%Y-%m-%d"),
DT.datetime.strptime('2010-03-19', "%Y-%m-%d"),]
values = [123,678,987,345]
d1 = zip(ddata,values)
def nplot(data):
x = [date for (date, value) in data]
y = [value for (date, value) in data]
# Set the stage
fig, ax = plt.subplots()
graph = fig.add_subplot(111)
# Plot the data as a red line with round markers
graph.plot(x,y,'r-o')
days = dates.DayLocator(interval=7) # every week
months = dates.MonthLocator() # every month
# Create locators and ticks
ax.xaxis.set_minor_locator(days)
ax.xaxis.set_minor_formatter(dates.DateFormatter('%d'))
ax.xaxis.set_major_locator(months)
ax.xaxis.set_major_formatter(dates.DateFormatter('\n\n%b'))
ax.xaxis.grid(True, which="major", linewidth=2)
# Now how do I align a rectangle with specific dates?
gca().add_patch(Rectangle((data[0][0], 1000),
data[2][0], 1000, facecolor='w', alpha=0.9)) # doesn't work
plt.show()
nplot(d1)
With this I get the currently set minor ticks
locs = ax.xaxis.get_minorticklocs()
And with this I write the rectangle. Odd, the location of the left side is a 6-digit float, but the location for the right side is the number of days since the left side. No idea how that works, but it seems to...
gca().add_patch(Rectangle((locs[0], 0), 7, 1000, facecolor='w', alpha=0.9))
And this is what I wanted to do from the beginning: to mark recurring ranges.
locs = ax.xaxis.get_minorticklocs()
loc_len = len(locs)
zloc = zip(locs, [7] * loc_len) # Seven-day loops
for i in zloc[::2]:
gca().add_patch(Rectangle((i[0], 0), i[1], 1000, facecolor='w', alpha=0.9))
However, this won't work if I decide to box months, as each month has a different number of days. #Greg's suggestion of using fill_between is another option, but it will set its limits in relation to the data, not the scale (which is OK, I guess):
xloc = zip(x[:-1], x[1:])
for i in xloc[::2]:
ax.fill_between(i, 0, 1200, facecolor='w', alpha=0.5)
ylim(0, 1200)
plt.show()
This is my first time asking a Python question online. I have always been able to find answers to my questions on this site..until now. I am trying to plot data that were developed using the Index Sequential Method, which is a technique for projecting historical data into the future. I have 105 charts that each cover 47 years of data. The first chart x-axis ranges from 1906-1952, the second 1907-1953, thir 1908-1954, etc. My problem is when I get to 1963, which is when the 47th year reverts back to the begining (1906). So the 1963 chart xaxis would look like this: 1963, 1964, 1965,...2008,2009,2010,1906. The 1964 chart xaxis would look like this: 1964, 1965, 1967,...2009, 2010, 1906, 1907.
I can get the data to plot fine, I just need help figuring out how to format the xaxis to accept the unique wrap-around situation when it occurs.
There are three charts per page (ax1, ax2, and ax3). yearList and chartList are the x and y data, respectively. The code below is part of a for loop that creates the yearList and chartList data sets, and it creates the charts with the wrong xaxis labels.
import matplotlib, pyPdf
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as tkr
from matplotlib.ticker import MultipleLocator
import matplotlib.figure as figure
plt.rcParams['font.family'] = 'Times New Roman'
locator = mdates.YearLocator(2)
minorLocator = MultipleLocator(1)
dateFmt = mdates.DateFormatter('%Y')
datemin = min(yearList)
datemax = max(yearList)
fig, (ax1, ax2, ax3) = plt.subplots(3,1,sharex=False)
#3X3 Top to bottom
ax1.bar(yearList1, chartList1, width=200, align='center')
ax2.bar(yearList2, chartList2, width=200, align='center')
ax3.bar(yearList3, chartList3, width=200, align='center')
axList = [ax1, ax2, ax3]
for ax in axList:
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(dateFmt)
ax.xaxis.set_minor_locator(minorLocator)
ax.set_xlim(datemin - timedelta(365), datemax + timedelta(365))
ax.grid(1)
ax.set_ylim(0,30)
ax.set_yticks(np.arange(0, 31, 5))
ax.yaxis.set_minor_locator(minorLocator)
#Rotate tick labels 90 degrees
xlabels = ax.get_xticklabels()
for label in xlabels:
label.set_rotation(90)
fig.tight_layout()
plt.subplots_adjust(right=0.925)
plt.savefig('%s\\run.pdf' % outDir)
You are making a bar graph, which means the x-posistion has little to no meaning aside from the labels, so don't try to plot the bars vs their date, plot them against the integers, and then label them as you wish:
from itertools import izip
fig, axeses = plt.subplots(3,1,sharex=False)
#3X3 Top to bottom
for yl, cl, ax in izip([yearList1, yearList2, yearList3],
[chartList1, chartList2, chartist3],
axeses):
ax.bar(range(len(cl)), cl, align='center')
ax.set_ylim(0,30)
ax.set_yticks(np.arange(0, 31, 5))
ax.yaxis.set_minor_locator(minorLocator)
xlabels = [dateFmt(xl) for xl in yl] # make a list of formatted labels
ax.set_xticks(range(len(cl))) # put the tick markers under your bars
ax.set_xticklabels(xlabels) # set the labels to be your formatted years
#Rotate tick labels 90 degrees
for label in ax.get_xticklabels():
label.set_rotation(90)
# you only need to do this once
fig.tight_layout()
fig.subplots_adjust(right=0.925)
fig.savefig('%s\\run.pdf' % outDir)
Also see the demo and the docs set_xticks and set_xticklabels
You can use the ax.set_ticklabels() function to set the labels.
Example:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot([1, 2, 3, 4], [10, 20, 25, 30])
ax.xaxis.set_ticklabels(["foo" , "bar", "ouch"])
plt.show()
So, just add the transformation that you need, and create the labels list.
maybe something like this:
range = 47
yearList = [1967, 1968,..., last year]
range_of_years = map(lambda x: range(year,year + range), yearList)
for i in range(len(axis_list)):
axis_list[i].xaxis.set_ticklabels(years_list[i])