I'd like to superimpose one plot over another (they are polygons, really in some lat/lon space, using geopandas, but the plot is simply derived from matplotlib)
I have:
figZ, axZ = plt.subplots(1, figsize=(11,8.5))
Sfig = X.plot(ax=axZ, color='white', edgecolor='black', lw=0.7)
Y.plot(ax=axZ, color='white', edgecolor='black', lw=0.7, alpha=0.3)
How do I set Sfig's color to "no-fill" instead of white? The way it is now it "blurs" my Sfig image (X.plot) by the alpha of the Y.plot one. How do I set "color" to actually transparent?
I don't expect upvotes, but this is what I found as solution. I'll vote up better ones if they exist:
Sfig = X.plot(ax=axZ, facecolor="none",
edgecolor='black', lw=0.7)
I know this post doesn't mention seaborn, but I suspect a lot of people end up here asking this question for seaborn also (as I did).
The top answer almost works for seaborn boxplots, you just need to pass it as boxprops.
sns.boxplot(data=data, x=x, y=y, hue=hue, boxprops=dict(facecolor="none"))
NOTE: I emphasise that this solution only works for boxplots. There is an open, more general, feature request for this functionality in seaborn.
To disable facecolor just set with the value (0, 0, 0, 0), i.e.,
Sfig = set_facecolor((0,0,0,0))
Related
I want to make a seaborn pointplot that has transparency so that I can clearly see the points located behind others of a different color.
I tried adding "alpha=0.3" to the call to pointplot and also tried the same within a catplot with kind='point'; however, neither of these results in the desired transparency (no error message is produced either).
sns.pointplot(x='aamm', y='posrate', hue='AA:XX', hue_order=[1,0], data=data, dodge=True, palette=palette, alpha=0.3)
I was hoping to get a plot with transparent points, but instead, I got one with normal opaque points. The dodge option doesn't seem to produce any noticeable effect either, in terms of separating overlapping points of different color.
Is there a way to add transparency to a seaborn pointplot or use something else to get a similar effect?
Thank you.
To the extent of my knowledge there is no more an alpha parameter that can be directly set in seaborn.
You can do the following thou:
Sample dataframe
df = pd.DataFrame(np.random.randint(low=0, high=1000, size=(50, 5)))
Plotting
ax = sns.pointplot(x=0, y=1, data=df, dodge=True,plot_kws=dict(alpha=0.3))
plt.setp(ax.collections, alpha=.3) #for the markers
plt.setp(ax.lines, alpha=.3) #for the lines
I'm trying to change the x axis for my graphs but it's only going through for one of them. My other graph has not changed at all. Here is the code:
fig, (gr0, gr1) = plt.subplots(ncols=2, constrained_layout=True, figsize = (17,7))
#gr0
gr0.plot(data['g1'])
gr0.set_title('text 1')
#gr1
gr1.plot(data['g2'])
gr1.set_title('text 2')
plt.xticks(fontsize=8, rotation=45)
plt.show()
Graphs when the code is ran:
As you can tell by the picture, only the graph on the right has the x-axis updated to where the text is rotated and clearly visible. The other one is still the same :(
The
plt.xticks(..., rotation=45)
call might feel like it applies to the whole figure,
when it's phrased that way.
But behind the scenes it's really making a gca() call
and manipulating that, which of course is gr1 at that point.
You could make a pair of xticks calls,
much as you're already doing for title.
But the fact that you asked about this plot's behavior on SO
indicates that the way it's phrased is not a good match
for clearly communicating the intent.
So let's re-phrase it slightly, avoiding that global.
labels = [
'2022-05-21',
'2022-05-25',
'2022-05-29',
]
gr0.set_xticks(labels=labels, rotation=45)
gr1.set_xticks(labels=labels, rotation=45)
Or consider moving to import seaborn.
In which case the idiom would be the somewhat simpler
gr0.grid.set_xticklabels(rotation=45)
gr1.grid.set_xticklabels(rotation=45)
You can set it per axis using ax.tick_params(labelsize=8, labelrotation=45).
ig, (gr0,gr1) = plt.subplots(ncols=2, constrained_layout=True, figsize = (17,7))
#gr0
gr0.plot(data['g1'])
gr0.set_title('text 1')
gr0.tick_params(labelsize=8, labelrotation=45)
#gr1
gr1.plot(data['g2'])
gr1.set_title('text 2')
gr1.tick_params(labelsize=8, labelrotation=45)
plt.show()
This question is similar to this one asked 6 years ago. However, their solution is not quite solving my problem; unlike their question, I am dealing with multiple legends, some of which are getting cut off.
I'm trying to create a figure containing multiple legends that sit outside the axes of my graph. I'm following the matplotlib documentation's instructions for creating multiple legends, using add_artist to add all but the final legend to my axes. I then use the bbox_extra_artists parameter in my savefig call as described in the above question to include all my legend objects. As seen in this example output image, the wider legend still gets cut off on the right side.
The code used to generate this plot:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.gca()
for x in [0, 1, 2]:
ax.bar(x+0.5, x+1, width=1, color=['red', 'blue', 'green'][x])
handle1 = plt.Line2D((0,1), (0,0), color='purple')
lgd1 = ax.legend([handle1], ['label1 is very long'], bbox_to_anchor=(1, 1))
ax.add_artist(lgd1)
handle2 = plt.Line2D((0,1), (0,0), color='orange')
lgd2 = ax.legend([handle2], ['label2'], bbox_to_anchor=(1, 0.9))
plt.savefig('output.png', bbox_extra_artists=(lgd1,lgd2), bbox_inches='tight')
Notably, if I change the order in which the legends are added (adding the wider legend first), the problem goes away and both legends are visible as seen here:
handle2 = plt.Line2D((0,1), (0,0), color='orange')
lgd2 = ax.legend([handle2], ['label2'], bbox_to_anchor=(1, 0.9))
ax.add_artist(lgd2)
handle1 = plt.Line2D((0,1), (0,0), color='purple')
lgd1 = ax.legend([handle1], ['label1 is very long'], bbox_to_anchor=(1, 1))
plt.savefig('output.png', bbox_extra_artists=(lgd1,lgd2), bbox_inches='tight')
For my actual project (which has to handle a dynamic number of legends), I've made it figure out which legend is "longest" and always add that legend last to work around this problem. However, this feels messy and it doesn't allow for adding more legends on other sides of the figure (e.g., I cannot add an x-axis legend below the graph without it getting cut off, since only one legend can be added "last").
Is this an intractable bug in matplotlib, or is there a tidy solution I'm missing?
So I need to make this plot in python. I wish to remove my legend's border. However, when I tried the different solutions other posters made, they were unable to work with mine. Please help.
This doesn't work:
plt.legend({'z$\sim$0.35', 'z$\sim$0.1','z$\sim$1.55'})
plt.legend(frameon=False)
plt.legend({'z$\sim$0.35', 'z$\sim$0.1','z$\sim$1.55'})
plt.legend.get_frame().set_linewidth(0.0)
plt.legend({'z$\sim$0.35', 'z$\sim$0.1','z$\sim$1.55'}, 'Box', 'off')
Additionally, when I plotted, I imported two different files and graphed them with a line and with circles respectively. How could I put a line or a circle within the legend key?
The plot:
It's very strange because the command :
plt.legend(frameon=False)
Should work very well.
You can also try this command, to compare :
plt.legend(frameon=None)
You can also read the documentation on this page about plt.legend
I scripted something as example to you :
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0,4,8,13])
y = np.array([0,1,2,3])
fig1, ((ax1, ax2)) = plt.subplots(1, 2)
ax1.plot(x,y, label=u'test')
ax1.legend(loc='upper left', frameon=False)
ax2.plot(x,y, label=u'test2')
ax2.legend(loc='upper left', frameon=None)
plt.show()
Try this if you want to draw only one plot (without subplot)
plt.legend({'z$\sim$0.35', 'z$\sim$0.1','z$\sim$1.55'}, frameon=False)
It is enough one plt.legend. The second one rewrites the first one.
Make sure frameon = False is together with the positional argument in plt.legend(...) if you want to specify the position as well as remove the border. If these arguments are written separately or in sequential, there's an issue of overwriting and the desired effect may not be achieved.
Correct!
plt.legend(loc="lower right", frameon=False)
May not give desired effect when written like this!
plt.legend(loc="lower right") & plt.legend(frameon=False)
I have a matplotlib.PatchCollection that I want to add to a plot. But I also have Text and other Patches I am adding straight onto the plot. So it looks like this:
node.shape = RegularPolygon((node.posX, node.posY),
6,
radius = node.radius,
edgecolor = 'none',
facecolor = node.fillColor,
zorder = node.zorder)
self.patches.append(node.shape)
self.p = PatchCollection(self.patches, edgecolor = 'none', match_original=True )
self.plotAxes.add_collection(self.p)
#Two previously instantiated patches (they are visible)
self.plotAxes.add_artist(selectionRect)
self.plotAxes.add_artist(brushShape)
self.plotCanvas.draw()
I want my Patches in the collection to be drawn first and then the selctionRect and brushShape to be drawn afterwards because they can overlap the Patches in the collection. If they do, they should be visible. However, my plot always shows the Patches in the collection as if they've been drawn last. How can I get around this? Any help is appreciated.
Edit: One thing that appears to work is to keep 2 PatchCollections. However, when I do this, it seems that I can never set the visibilities to false. Does the PatchCollection set the reset the values or something?
As Adam said in the comments you want to set zorder, which sets what order things layer when they are drawn on top of each other, things with higher zorder will overlap things with lower zorder.
Everything has a default zorder, but you can over-ride that value by adding the zorder kwarg to the function call. It is an Artist kwarg, so basically ever plotting function should respect it (and if you find one that does not submit a bug report to the github site)
ex
plt.figure()
ax = plt.gca()
ax.plot(range(5), zorder=2, lw=10)
ax.plot(range(5)[::-1], zorder=1, lw=10)
vs
plt.figure()
ax = plt.gca()
ax.plot(range(5), zorder=1, lw=10)
ax.plot(range(5)[::-1], zorder=2, lw=10)
zorder demo