Related
I have a plot with a very wide legend.
I've managed to move the legend out of the plot so that it doesn't cover it, but the legend is too wide for the window and not completely visible. This could be corrected if I knew how to move plot and legend towards the left where there is spare space.
This is what I mean:
What instruction would allow me to do this?
My current code:
f,ax=plt.subplots(1)
f.set_size_inches(14,10.5)
...
plt.legend(bbox_to_anchor=(1,1), loc="upper left")
plt.show()
Thank you
You can try adjusting the margins. The line to do that is f.subplots_adjust(left=0.05, bottom=0.07, right=0.95, top=0.95, wspace=0, hspace=0). These values can be controlled from the button to the left of the save button on the bottom toolbar. So, you can try playing with those in the gui, then when you find a value you like or that works, enter them in the suggested line of code.
Then you code should look like .
f,ax=plt.subplots(1)
f.set_size_inches(14,10.5)
...
plt.legend(bbox_to_anchor=(1,1), loc="upper left")
f.subplots_adjust(left=0.05, bottom=0.07, right=0.95, top=0.95, wspace=0, hspace=0)
plt.show()
I'm working with TraMineR and I don't know how to arrange my plot. So basically what i would like to have the legend under the plot and to remove the space between the x and y axis. Any help is welcomed.
The plot:
Sample code:
seqdplot(Activities.seq, with.legend=FALSE)
legend("bottom", legend=attr(Activities.seq, "labels"),
fill=attr(Activities.seq, "cpal"),
inset=-.1, bty="o", xpd=NA, cex=.75,ncol=3)
The family of seqplot functions offers a series of arguments to control the legend as well as the axes. Look at the help page of seqplot (and of plot.stslist.statd for specific seqdplot parameters).
For instance, you can suppress the x-axis with axes=FALSE, and the y-axis with yaxis=FALSE.
To print the legend you can let seqdplot display it automatically using the default with.legend=TRUE option and control it with for examples cex.legend for the font size, ltext for the text. You can also use the ncol argument to set the number of columns in the legend.
The seqplot functions use by default layout to organize the graphic area between the plots and the legend. If you need more fine tuning (e.g. to change the default par(mar=c(5.1,4.1,4.1,2.1)) margins around the plot and the legend), you should create separately the plot(s) and the legend and then organize them yourself using e.g. layout or par(mfrow=...). In that case, the separate graphics should be created by setting with.legend=FALSE, which prevents the display of the legend and disables the automatic use of layout.
The color legend is easiest obtained with seqlegend.
I illustrate with the mvad data that ships with TraMineR. First the default plot with the legend. Note the use of border=NA to suppress the too many vertical black lines.
library(TraMineR)
data(mvad)
mvad.scode <- c("EM", "FE", "HE", "JL", "SC", "TR")
mvad.seq <- seqdef(mvad, 17:86,
states = mvad.scode,
xtstep = 6)
# Default plot with the legend,
seqdplot(mvad.seq, border=NA)
Now, we suppress the x and y axes and modify the display of the legend
seqdplot(mvad.seq, border=NA,
axes=FALSE, yaxis=FALSE, ylab="",
cex.legend=1.3, ncol=6, legend.prop=.11)
Here is how you can control the space between the plot and the x and y axes
seqdplot(mvad.seq, border=NA, yaxis=FALSE, xaxis=FALSE, with.legend=FALSE)
axis(2, line=-1)
axis(1, line=0)
Creating the legend separately and reducing the left, top, and right margins around the legend
op <- par(mar=c(5.1,0.1,0.1,0.1))
seqlegend(mvad.seq, ncol=2, cex=2)
par(op)
I have a subplot with an external, horizontal legend (figure legend), and super title (suptitle). I would like to align them on the bottom of the text, vertically. I set the vertical position of the title with fig.suptitle('title', ha='left', y=placement). When I try to set the legend's location with fig.legend(handles, labels, loc=(0.65, placement)), It is not aligned. I suspect this is an issue with the point the objects are aligned on and that the legend has a border... so I changed the padding of the legend to 0, but still have to tweak it.
How could I explicitly set the anchor point, or node, of the suptitle and legend?
EDIT
Image attached below. I believe I have solved the problem with setting the suptitle parameter va='bottom, and legend parameters borderpad=0.0, borderaxespad=0. Now, if I do have a border, how would I do this? I would also like to know how to explicitly set the anchor point of the legend.
SOLUTION
When you set the bbox_to_anchor parameter in the legend, it basically changed where the legend is clipped to. If the bbox has no height or width (2-tuple), it is a point. The loc parameter is then the point on the legend frame that is anchored to the bbox. When loc is used on it's on, the bbox is determined by MPL.
Let's say I wanted the title on the left, legend on the right (with no box), and horizontally aligned at the bottom. Mmy solution would look like:
fig.suptitle('title', ha='left', va='bottom', y=placement, x=0.02)
fig.legend(handles, labels,
loc='lower right',
bbox_to_anchor=(0.98, placement),
borderpad=0.0,
borderaxespad=0,
ncol=3,
)
I would like to position a text box with keyword arguments like those used with legend 'loc' option, i.e. 'upper left', 'upper right', 'lower right', 'lower left'.
The basic purpose is to align the text box with legend.
I found a suggestion here : automatically position text box in matplotlib but it still uses coordinates with which I have to play to get what I want, especially if I want to put it on the right of the plot area depending on the length of the text put in the box. Unless I can set one of the right corner of the text box as the reference for coordinates.
You can do this with matplotlib's AnchoredText. As shown here:
automatically position text box in matplotlib
In brief:
from matplotlib.offsetbox import AnchoredText
anchored_text = AnchoredText("Test", loc=2)
ax.plot(x,y)
ax.add_artist(anchored_text)
Each loc number corresponds to a position within the axes, for example loc=2 is "upper left". The full list of positions is given here : http://matplotlib.org/api/offsetbox_api.html
How about setting the location of the text relative to the legend? The trick is, to find the location of the legend you have to draw it first then get the bbox. Here's an example:
import matplotlib.pyplot as plt
from numpy import random
# Plot some stuff
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(random.rand(10))
# Add a legend
leg = ax.legend('line', loc = 'upper right')
# Draw the figure so you can find the positon of the legend.
plt.draw()
# Get the Bbox
bb = leg.legendPatch.get_bbox().inverse_transformed(ax.transAxes)
# Add text relative to the location of the legend.
ax.text(bb.x0, bb.y0 - bb.height, 'text', transform=ax.transAxes)
plt.show()
On the other hand, if you only need to define the location of the text from the right you can set the horizontal alignment to right like this:
plt.text(x, y, 'text', ha = 'right')
I set matplotlib to put ticks outside the plot area but now they overlap on the corresponding labels. the tick_params method does not provide any option to set the corresponding labels position.
So I guess I will have to write my own function using text() method. In the meanwhile does any one has a better suggestion?
To shift the tick labels relative to the ticks use pad. Compare
ax.tick_params(direction='out', pad=5)
plt.draw()
with
ax.tick_params(direction='out', pad=15)
plt.draw()