Change order of axes drawn in matplotlib figure - python

I have a figure in matplotlib where two axes overlap one-another. The axes draw according to the order in which they were created in the code, as shown when I print fig.axes, which returns [<matplotlib.axes._subplots.AxesSubplot object at 0x0000021C7417B320>, <matplotlib.axes._subplots.AxesSubplot object at 0x0000021C72371630>]. I would like to change the order so that the second axes created draws first. The property fig.axes is not writeable, so I unfortunately can't create a new list with the order I need and then assign it. I've also tried using ax.set_zorder() where I specified ax1.set_zorder(0) and ax2.set_zorder(1), but this did not work, and neither did the reverse or larger integer values. I can't seem to find anything in the documentation that would allow me to change the order in which axes are drawn, does anyone know of a way?
Purpose
As you can see, the grey year labels along the x-axis are covered by the black date call-outs. The year labels are part of ax1 and the date labels ax2. I'd like to switch the order so that ax1 is drawn above ax2, so as to not cover the year text.
Thanks for any help and suggestions!

Related

python matplotlib - retrieve xaxis_major_locator as time value

I am plotting a timeserie with matplotlib (timeserie looks like the following):
Part of the code that i use sets major locator for each day at 0AM:
fig, ax = plt.subplots(figsize=(20, 3))
mpf.candlestick_ohlc(ax,quotes, width=0.01)
ax.xaxis_date()
ax.xaxis.set_major_locator(mpl.dates.DayLocator(interval=1) )
I would like to plot a darker background on the chart for each day between 16pm and 8am, and planning to use axvspan for that task. Considering that axvspan takes as argument axvspan(xmin, xmax) I was wondering if it would be possible to retrieve the xaxis_major_locator as a x value in order to pass it to axvspan as axvspan(xmin=major_locator-3600s, xmax=major_locator+3600s)
Edit: I found that function in the docs: http://matplotlib.org/2.0.0rc2/api/ticker_api.html#matplotlib.ticker.Locator
If anyone knows how to returns a list of ticker location from the Xaxis_major with it let me know. Thanks.
Edit2: if i use print(ax.xaxis.get_major_locator()) i receive as a return <matplotlib.dates.DayLocator object at 0x7f70f3b34090> How do i extarct a list of tick location from that?
ok found it...
majors=ax.xaxis.get_majorticklocs()

pyplot.scatter(dataframe) vs. dataframe.plot(kind='scatter')

I have several pandas dataframes. I want to plot several columns against one another in separate scatter plots, and combine them as subplots in a figure. I want to label each subplot accordingly. I had a lot of trouble with getting subplot labels working, until I discovered that there are two ways of plotting directly from dataframes, as far as I know; see SO and pandasdoc:
ax0 = plt.scatter(df.column0, df.column5)
type(ax0): matplotlib.collections.PathCollection
and
ax1 = df.plot(0,5,kind='scatter')
type(ax1): matplotlib.axes._subplots.AxesSubplot
ax.set_title('title') works on ax1 but not on ax0, which returns
AttributeError: 'PathCollection' object has no attribute 'set_title'
I don't understand why the two separate ways exist. What is the purpose of the first method using PathCollections? The second one was added in 17.0; is the first one obsolete or has it a different purpose?
As you have found, the pandas function returns an axes object. The PathCollection object can be interpreted as an axes object as well using the "get current axes" function. For instance:
plot = plt.scatter(df.column0, df.column5)
ax0 = plt.gca()
type(ax0)
< matplotlib.axes._subplots.AxesSubplot at 0x10d2cde10>
A more standard way you might see this is the following:
fig = plt.figure()
ax0 = plt.add_subplot()
ax0.scatter(df.column0, df.column5)
At this point you are welcome to do "set" commands such as your set_title.
Hope this helps.
The difference between the two is that they are from different libraries. The first one is from matplotlib, the second one from pandas. They do the same, which is create a matplotlib scatter plot, but the matplotlib version returns a collection of points, whereas the pandas version returns a matplotlib subplot. This makes the matplotlib version a bit more versatile, as you can use the collection of points in another plot.

Show only the n'th ticklabel in a pandas boxplot

I am new to pandas and matplotlib, but not to Python. I have two questions; a primary and a secondary one.
Primary:
I have a pandas boxplot with FICO score on the x-axis and interest rate on the y-axis.
My x-axis is all messed up since the FICO scores are overwriting each other.
I'd like to show only every 4th or 5th ticklabel on the x-axis for a couple of reasons:
in general it's less chart-junky
in this case it will allow the labels to actually be read.
My code snippet is as follows:
plt.figure()
loansmin = pd.read_csv('../datasets/loanf.csv')
p = loansmin.boxplot('Interest.Rate','FICO.Score')
I saved the return value in p as I thought I might need to manipulate the plot further which I do now.
Secondary:
How do I access the plot, subplot, axes objects from pandas boxplot.
p above is an matplotlib.axes.AxesSubplot object.
help(matplotlib.axes.AxesSubplot) gives a message saying:
'AttributeError: 'module' object has no attribute 'AxesSubplot'
dir(matplotlib.axes) lists Axes, Subplot and Subplotbase as in that namespace but no AxesSubplot. How do I understand this returned object better?
As I explored further I found that one could explore the returned object p via dir().
Doing this I found a long list of useful methods, amongst which was set_xticklabels.
Doing help(p.set_xticklabels) gave some cryptic, but still useful, help - essentially suggesting passing in a list of strings for ticklabels.
I then tried doing the following - adding set_xticklabels to the end of the last line in the above code effectively chaining the invocations.
plt.figure()
loansmin = pd.read_csv('../datasets/loanf.csv')
p=loansmin.boxplot('Interest.Rate','FICO.Score').set_xticklabels(['650','','','','','700'])
This gave the desired result. I suspect there's a better way as in the way matplotlib does it which allows you to show every n'th label. But for immediate use this works, and also allows setting labels where they are not periodic for whatever reason, if you need that.
As usual, writing out the question explicitly helped me find the answer. And if anyone can help me get to the underlying matplotlib object that is still an open question.
AxesSubplot (I think) is just another way to get at the Axes in matplotlib. set_xticklabels() is part of the matplotlib object oriented interface (on axes). So, if you were using something like pylab, you might use xticks(ticks, labels), but instead here you have to separate it into different calls ax.set_xticks(ticks), ax.set_xticklabels(labels). (where ax is an Axes object).
Let's say you only want to set ticks at 650 and 700. You could do the following:
ticks = labels = [650, 700]
plt.figure()
loansmin = pd.read_csv('../datasets/loanf.csv')
p=loansmin.boxplot('Interest.Rate','FICO.Score')
p.set_xticks(ticks)
p.set_xticklabels(labels)
Similarly, you can use set_xlim and set_ylim to do the equivalent of xlim() and ylim() in plt.

Matplotlib adding overlay labels to an axis

In matplotlib I wish to know the cleanest and most robust means of overlaying labels onto an axis. This is probably best demonstrated with an example:
While normal axis labels/ticks are placed every 5.00 units additional labels without ticks have been overlayed onto the axis (this can be seen at 1113.75 which partially covers 1114.00 and 1105.00 which is covered entirely). The labels also have the same font and size as their normal, ticked, counterparts with the background (if any) going right up to the axis (as a tick mark would).
What is the simplest way of obtaining this effect in matplotlib?
Edit
Following on from #Ken's suggestion I have managed to obtain the effect for an existing tick/label by using ax.yaxis.get_ticklines and ax.yaxis.get_ticklabels to both remove the tick marker and change the background/font/zorder of a label. However, I am unsure how best to add a new tick/label to an axis.
In other words I am looking for a function add_tick(ax.yaxis, loc) that adds a tick at location loc and returns the tickline and ticklabel objects for me to operate on.
I haven't ever tried to do that, but I think that the Artist tutorial might be helpful for you. In particular, the last section has the following code:
for line in ax1.yaxis.get_ticklines():
# line is a Line2D instance
line.set_color('green')
line.set_markersize(25)
line.set_markeredgewidth(3)
I think that using something like line.set_markersize(0) might make the markers have size zero. The difficult part might be finding the ones that need that done. It is possible that the line.xdata or line.ydata arrays might contain enough information to isolate the ones you need. Of course, if you are manually adding the tick marks, it is possible that as you do that the instance gets returned, so you can just modify them as you create them.
The best solution I have been able to devise:
# main: axis; olocs: locations list; ocols: location colours
def overlay_labels(main, olocs, ocols):
# Append the overlay labels as ticks
main.yaxis.set_ticks(np.append(main.yaxis.get_ticklocs(), olocs))
# Perform generic formatting to /all/ ticks
# [...]
labels = reversed(main.yaxis.get_ticklabels())
markers = reversed(main.yaxis.get_ticklines()[1::2]) # RHS ticks only
glines = reversed(main.yaxis.get_gridlines())
rocols = reversed(ocols)
# Suitably format each overlay tick (colours and lines)
for label,marker,grid,colour in izip(labels, markers, glines, rocols):
label.set_color('white')
label.set_backgroundcolor(colour)
marker.set_visible(False)
grid.set_visible(False)
It is not particularly elegant but does appear to work.

matplotlib set yaxis label size

How can I change the size of only the yaxis label?
Right now, I change the size of all labels using
pylab.rc('font', family='serif', size=40)
but in my case, I would like to make the y-axis label larger than the x-axis. However, I'd like to leave the tick labels alone.
I've tried, for example:
pylab.gca().get_ylabel().set_fontsize(60)
but I only get:
AttributeError: 'str' object has no attribute 'set_fontsize'
So, obviously that doesn't work. I've seen lots of stuff for tick sizes, but nothing for the axis labels themselves.
If you are using the 'pylab' for interactive plotting you can set the labelsize at creation time with pylab.ylabel('Example', fontsize=40).
If you use pyplot programmatically you can either set the fontsize on creation with ax.set_ylabel('Example', fontsize=40) or afterwards with ax.yaxis.label.set_size(40).

Categories