There are a number of ways to do what you want. To add to what @inalis and @Navi already said, you can use the bbox_to_anchor
keyword argument to place the legend partially outside the axes and/or decrease the font size.
Before you consider decreasing the font size (which can make things awfully hard to read), try playing around with placing the legend in different places:
So, let's start with a generic example:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$' % i)
ax.legend()
plt.show()
![alt text](https://i.stack.imgur.com/LQ8xkm.png)
If we do the same thing, but use the bbox_to_anchor
keyword argument we can shift the legend slightly outside the axes boundaries:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$' % i)
ax.legend(bbox_to_anchor=(1.1, 1.05))
plt.show()
![alt text](https://i.stack.imgur.com/OtE5Um.png)
Similarly, make the legend more horizontal and/or put it at the top of the figure (I'm also turning on rounded corners and a simple drop shadow):
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
line, = ax.plot(x, i * x, label='$y = %ix$'%i)
ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
ncol=3, fancybox=True, shadow=True)
plt.show()
![alt text](https://i.stack.imgur.com/zgtBlm.png)
Alternatively, shrink the current plot's width, and put the legend entirely outside the axis of the figure (note: if you use tight_layout()
, then leave out ax.set_position()
:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'%i)
# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()
![alt text](https://i.stack.imgur.com/v34g8m.png)
And in a similar manner, shrink the plot vertically, and put a horizontal legend at the bottom:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
line, = ax.plot(x, i * x, label='$y = %ix$'%i)
# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
box.width, box.height * 0.9])
# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
fancybox=True, shadow=True, ncol=5)
plt.show()
![alt text](https://i.stack.imgur.com/cXcYam.png)
Have a look at the matplotlib legend guide. You might also take a look at plt.figlegend()
.
The size is not applied to the legend since size
is outside aes_string
. Furtermore, the work with ggplot
will be much easier if you create an additional column indicating whether vendor == "z"
.
Here's a solution for part 1:
df$vendor_z <- df$vendor=="z" # create a new column
ggplot(df) +
aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
geom_point() +
scale_size_manual(values = c(3, 5), guide = FALSE) +
guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))
Note that vendor_z
is as argument of aes_string
. This will tell ggplot
to create a legend for the size
characteristic. In the function scale_size_manual
, the values for size
are set. Furthermore, guide = FALSE
avoids a second legend for size
only. Finally, the size
values are applied to the color
legend.
![enter image description here](https://i.stack.imgur.com/HqlXL.png)
Part2: a "donut" symbol
The size of the lines for circles cannot be modified in ggplot
. Here is a workaround:
ggplot(df) +
aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
geom_point() +
geom_point(data = df[df$vendor_z, ], aes(x = x, y = y),
size = 3, shape = 21, fill = "white", show_guide = FALSE) +
scale_size_manual(values = c(3, 5), guide = FALSE) +
guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))
Here, a single point is drawn using geom_point
and a subset of the data (df[df$vendor_z, ]
). I chose a size
of 3
since this is the value of the smaller circles. The shape
21
is a circle for which a fill
colour could be specified. Finally, show_guide = FALSE
avoids that the legend characteristics are overwritten by the new shape
.
![enter image description here](https://i.stack.imgur.com/7fIjs.png)
Edit: part 3: Add lines
You could suppress the legend for geom_line
with the argument show_guide = FALSE
:
ggplot(df) +
aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
geom_point() +
geom_line(size=1.5, show_guide = FALSE) + # this is the only difference
scale_size_manual(values = c(3, 5), guide = FALSE) +
guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))
![enter image description here](https://i.stack.imgur.com/Mg0Ql.png)
Best Answer
To change line width only in the legend you should use function
guides()
and then forcolour=
useguide_legend()
withoverride.aes=
and setsize=
. This will override size used in plot and will use new size value just for legend.To get points in legend and lines in plot workaround would be add
geom_point(size=0)
to ensure that points are invisible and then inguides()
setlinetype=0
to remove lines andsize=3
to get larger points.