matplotlib vertical space in the background - python

I've plated a bar graph where I set a default horizontal span:
plt.axhspan(0,2, color='yellow', alpha=0.25)
However it looks like that yellow area covers my original bars. How can I make a horizontal span to be in a background?

Use zorder and set zorder of the histogram higher than zorder of the hspan:
plt.hist(x, 50, normed=1, zorder=1)
plt.axhspan(0, 0.01, facecolor='yellow', zorder=0)

You can use zorder when plotting your graph.
For example with a scatter plot;
plt.axhspan(0, 2, color='yellow', alpha=0.25)
plt.scatter(X, Y, zorder=10)
This ensures your graph is on top of the axhspan.
zorder can be defined for many plt functions, just check the api, this is useful if you have many overlaying subplots for example.

Related

Is it possible to draw xticklabels on top of the xaxis?

I want to mark a specific x-axis position with a colored asterisk drawn on top of the x-axis.
I use an x-tick label as the marker (because I couldn't figure out if it is possible to place markers anywhere in the fig coords) at it's aligned properly but is drawn below the x-axis so it's partially covered.
MWE:
import numpy as np
import matplotlib.pyplot as plt
fig,ax=plt.subplots(1,1)
ax.scatter([-1,1],[1,1])
ax.set_xticks([0],minor=True)
ax.set_xticklabels(['*'],minor=True,color='r',fontsize=20,verticalalignment='center')
plt.setp(ax.spines.values(), linewidth=3)
plt.show()
That's what it looks like right now:
You can specify the coordinates of a scatter in a blended system (data coordinates for the y axis and axis coordinates for the x axis).
To then have the scatter marker above the spines set the zorder property of the scatter to something above 2.5.
import matplotlib.pyplot as plt
fig,ax=plt.subplots(1,1)
ax.scatter([-1,1],[1,1])
ax.scatter(0,0, s=100, marker="*", color="red",
transform=ax.get_xaxis_transform(), clip_on=False, zorder=3)
plt.show()
What you are looking for is zorder parameter. By using zorder = 0, you basically define the order of stacking of the plot sequence. 0 would send the axis/frame in the background putting the asterisk over the axis line as desired. I increased the size of the asterisk to highlight it.
ax.scatter([-1,1],[1,1])
ax.set_xticks([0],minor=True)
ax.set_xticklabels(['*'],minor=True,color='r',fontsize=30,verticalalignment='center')
plt.setp(ax.spines.values(), linewidth=3, zorder=0)
Alternatively, you can also specify the zorder for both plotting commands but use a higher zorder for the asterisk
ax.set_xticklabels(['*'],minor=True,color='r',fontsize=30,verticalalignment='center', zorder=2)
plt.setp(ax.spines.values(), linewidth=3, zorder=1)

matplotlib: axes border and tick mark/label locations

The end result I'm attempting to achieve is to have a "thicker" black boarder around my plot, along xmin, xmax, ymin, & ymax. I've tried a couple of different things (such as just drawing a rectangle on the plot, see below), but I have not been able to achieve the desired results for a few reasons.
Because I cannot just use the spines (I've set 2 of them to always be at 0), I need to add some other line or rectangle to create the desired border.
By default the first and last tick labels overhang the axes. I "overcame" this by changing the horizontal or vertical alignment, but they could still use some more padding. I know this is possible, but requires a transform and is a bit clunky.
Now I'd like to remove the first and last tick marks on both axis. This is because given the way the rectangle is drawn it is always inside the plot area, but the first and last tick mark are always outside it, regardless of how thick the rectangle is. Making the rectangle thicker only causes it to overlap the first and last tick label more, which the actual tick mark remains outside the rectangle.
Any other suggestions on how to achieve this kind of border while always maintaining an axis at 0, 0 would be welcomed. That is the overall desired result.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.patches import Rectangle
X = np.random.randint(low=-9, high=9, size=10)
Y = np.random.randint(low=-9, high=9, size=10)
fig, ax = plt.subplots()
ax.axis([-10, 10, -10, 10])
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.setp(ax.xaxis.get_majorticklabels()[0], ha='left')
plt.setp(ax.xaxis.get_majorticklabels()[-1], ha='right')
plt.setp(ax.yaxis.get_majorticklabels()[0], va='bottom')
plt.setp(ax.yaxis.get_majorticklabels()[-1], va='top')
patPlotBorder = ax.add_artist(Rectangle((-10, -10), 20, 20, fill=False, color='k', linewidth=2))
ax.grid(True)
fig.set_tight_layout(True)
ax.scatter(X, Y, c="b", marker="o", s=40)
plt.show()
Without changing much of your code, you can set the clip_on to False, such that the complete rectangle is shown.
border = Rectangle((-10, -10), 20, 20, fill=False, color='k', linewidth=3, clip_on=False)
ax.add_artist(border)
Since the gridlines are shown above the axes content, you have some grey line within the rectangle border.
Alternatively, you can use two axes. One with all the content and the modified spine positions etc., and one where you just make the spines bold and remove all the rest.
import numpy as np
import matplotlib.pyplot as plt
X = np.random.randint(low=-9, high=9, size=10)
Y = np.random.randint(low=-9, high=9, size=10)
fig, ax = plt.subplots()
ax2 = fig.add_subplot(111)
ax2.patch.set_visible(False)
ax2.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
for _, sp in ax2.spines.items():
sp.set_linewidth(3)
ax.axis([-10, 10, -10, 10])
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.setp(ax.xaxis.get_majorticklabels()[0], ha='left')
plt.setp(ax.xaxis.get_majorticklabels()[-1], ha='right')
plt.setp(ax.yaxis.get_majorticklabels()[0], va='bottom')
plt.setp(ax.yaxis.get_majorticklabels()[-1], va='top')
ax.grid(True)
fig.set_tight_layout(True)
ax.scatter(X, Y, c="b", marker="o", s=40)
plt.show()
You can access the individual grid lines by calling get_{x|y}gridlines(). Each grid line is an object of type Line2D, and you can change any of their properties, such as thickness, color, etc.
ax.get_xgridlines()[0].set_linewidth(5)
ax.get_xgridlines()[-1].set_linewidth(5)
ax.get_ygridlines()[0].set_linewidth(5)
ax.get_ygridlines()[-1].set_linewidth(5)

how to restart colormap when it gets to the last color? Or how to make the first colors in colormap last longer?

I have this 3d plot, but after a while the only color it puts is yellow, how can I make cmap start again from the first color instead of just plotting with yellow after a while?
Or how can I make the colors equally distributed? and prevent them from going very rapidly to yellow.
The colormap code line is the following
cm_gradient = plt.get_cmap('viridis')
This is how I call it
if numb_walkers in snapshot or finished_cluster==True:
col=np.arange(len(seeds_z_coordinates))
fig=plt.figure()
snapshots_taken.append(numb_walkers)
ax=fig.add_subplot(111, projection='3d')
ax.scatter(seeds_z_coordinates, seeds_y_coordinates, seeds_x_coordinates, s=1, c=col, marker='o', cmap=cm_gradient) # cmap=cmap)
label=str(numb_walkers)
plt.title("Crystal Growth by DLA")
ax.set_xlim3d(0, box_dim)
ax.set_ylim3d(0,box_dim)
ax.set_zlim3d(0,box_dim)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
plt.savefig("Gifs and images/{}_walkers.png".format(label), dpi=200)
plt.close()

Draw Circles on Top Level of Figure

I'm working on a figure where I'm trying to draw a circle on top of a combination colormap and contour plot. The circle keeps getting drawn under the contours instead of on top of them (see the figure below). I've tried reordering how I call imshow, contour, and Circle to see if I can get the circle to display on top, but I haven't had any luck. Is there a way to force Circle to be on the top most level of the figure? Thanks for your help!
Use the zorder kwarg. That controls which elements go on top of each other. So, in this case, you want to increase the zorder of the circle. You may need to experiment to find a zorder that gives you the result you require, but the rule is that higher zorder objects appear on top of lower zorder objects.
Its hard to know exactly without any of your code, but assuming you've used pcolormesh, contour and a Circle patch, this example shows the effect of not setting a zorder (white circle), and setting zorder=10 (red circle).
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
# Fake data
x = np.arange(100)
y = np.arange(100)
X, Y = np.meshgrid(x, y)
z = X**0.5 * Y**0.5
fig, ax = plt.subplots(1)
ax.set_aspect('equal')
ax.pcolormesh(X, Y, z, cmap='viridis')
ax.contour(X, Y, z, colors='k', linewidths=3)
circ1 = Circle((65, 65), 30, facecolor='None', edgecolor='w', lw=5)
circ2 = Circle((35, 35), 30, facecolor='None', edgecolor='r', lw=5, zorder=10)
ax.add_patch(circ1)
ax.add_patch(circ2)
plt.show()
Note that the white circle lies beneath the black contour lines, but by increasing the zorder to 10, the red circle lies on top of the contour lines.
You can set the zorder property of the plot object to force it to be on top of other plots within the same axes. A higher zorder value will appear on top of a lower zorder value.
plt.plot([1, 2], [1, 2], zorder=100)
By default, patches have a zorder of 1, 2D line objects have a zorder of 2 and text has a zorder of 3.

Matplotlib; Scatter plot marker, dot within circle

I'm plotting using the Matplotlib scatter plotter. For the markers I'd ideally like the outline of a circle with a dot inside (outside circle makes it clear there's something there, the dot is then more precise). I can achieve this if I simply plot it twice (once with the outline then again with the dot) but then my legend isn't correct. So my question is, is there any way to do this? Or am I looking for a solution that doesn't exist?
Example code:
import matplotlib.pyplot as plt
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
x_data = [0.5, 1, 1.5]
y_data = [0.06, 0.06, 0.01]
ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=80, marker='o', facecolors='none', edgecolors='black')
ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=10, marker='o', color='black')
plt.gcf().subplots_adjust(bottom=0.08, top=0.95, left=0.05, right=0.84)
ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5), fancybox=True, ncol=1, fontsize=17, labelspacing=1)
mng = plt.get_current_fig_manager()
mng.window.showMaximized()
plt.show()
And the example plot:
So yeah, would like something like those markers but with the ability to have them like that on the legend (unlike how it is currently split up into the two parts).
If any further information or clarification is needed, just ask. Thanks in advance for any/all help!
Clarification: I'm not sure I explained my goal well enough. I know I can get rid of one of the legends, but what I'm trying to achieve is a single legend entry with the combined marker (i.e. a circle with a 'dot' inside it). If I can't achieve then yes I'll just disable the legend for the outer circle but would quite like to get the marker used (which is a combination of two markers) on the plot to also be used on the legend.
You can use latex marker like that :
ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=80, marker=r'$\odot$', facecolors='none', edgecolors='black')
And then plot your graph only one time.
Have you tried removing the label from the circle? I used altered your code so that your first plot of the larger circles does not have a label. ax1.scatter(x_data, y_data, s=80, marker='o', facecolors='none', edgecolors='black')
This worked for me, but perhaps not for you?
You can mark your scatter plots and include only one in your legend:
Here's how :
a_ = ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=80, marker='o', facecolors='none', edgecolors='black')
b_ = ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=10, marker='o', color='black')
ax1.legend([a_],["Example legend entry"] , loc='center left', bbox_to_anchor=(1, 0.5), fancybox=True, ncol=1, fontsize=17, labelspacing=1)

Categories