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)
Related
I have an axis on which I plot some data and I have another twin axis which I use to draw grid lines at specific tick positions (other than the ticks of the original axis):
import matplotlib.pyplot as plt
import numpy as np
f, ax = plt.subplots()
ax.set_xlim([0, 1])
ax2 = ax.twiny()
ax2.set_xlim([0, 1])
ax2.set_xticks(np.linspace(0, 1, 11))
ax2.xaxis.grid()
x = np.linspace(0, 1, 100)
ax.plot(x, np.sin(x), label='sin(x)')
ax.legend()
plt.show()
Now this has the undesirable effect that the grid lines of the twin axes are drawn on top of the legend and line plot of the original axis. As far as I understand this is because matplotlib draws the axes in the order they were created and for that reason zorder won't help (because zorder only specifies the order among the artists of a single axis).
I know I could plot the data on the twin axis ax2 instead (followed by ax2.legend()) but I'd prefer to have the setup as is. Instead changing the order in which the two axes are drawn should solve the problem, but I couldn't figure out how to do that. There is f.get_axes() which seems to return the axes in the order they were created but no option to revert it.
Or maybe there exists even another solution?
You can change the zorder of the axes themselves.
ax.set_zorder(2)
ax2.set_zorder(1)
ax.patch.set_visible(False)
I have a matplotlib scatter plot with many markers:
plt.scatter(x_position,y_position,c=z_position,s=90, cmap=cm.bwr,linewidth=1,edgecolor='k')
Sometimes the markers overlap. I want the zorder of each to be based on the z_position of the individual marker.
Is this possible in a scatterplot or would I have to have an separate line for each data point with its own zorder value?
Thank you.
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0,1,0,1])
y = np.array([0,0,1,1])
z = np.array([8,4,6,2])
If you now call
plt.scatter(x, y, c=z, s=1000, marker="X",
cmap=plt.cm.bwr, linewidth=1, edgecolor='k')
markers overlap:
The last marker in the arrays is drawn last, hence the one with z=2 is in front.
You can sort the arrays by z to change the order of appearance.
order = np.argsort(z)
plt.scatter(x[order], y[order], c=z[order], s=1000, marker="X",
cmap=plt.cm.bwr, linewidth=1, edgecolor='k')
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)
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.
I want to draw a plot with matplotlib with axis on both sides of the plot, similar to this plot (the color is irrelevant to this question):
How can I do this with matplotlib?
Note: contrary to what is shown in the example graph, I want the two axis to be exactly the same, and want to show only one graph. Adding the two axis is only to make reading the graph easier.
You can use tick_params() (this I did in Jupyter notebook):
import matplotlib.pyplot as plt
bar(range(10), range(10))
tick_params(labeltop=True, labelright=True)
Generates this image:
UPD: added a simple example for subplots. You should use tick_params() with axis object.
This code sets to display only top labels for the top subplot and bottom labels for the bottom subplot (with corresponding ticks):
import matplotlib.pyplot as plt
f, axarr = plt.subplots(2)
axarr[0].bar(range(10), range(10))
axarr[0].tick_params(labelbottom=False, labeltop=True, labelleft=False, labelright=False,
bottom=False, top=True, left=False, right=False)
axarr[1].bar(range(10), range(10, 0, -1))
axarr[1].tick_params(labelbottom=True, labeltop=False, labelleft=False, labelright=False,
bottom=True, top=False, left=False, right=False)
Looks like this:
There are a couple of relevant examples in the online documentation:
Two Scales (seems to do exactly what you're asking for)
Dual Fahrenheit and Celsius
I've done this previously using the following:
# Create figure and initial axis
fig, ax0 = plt.subplots()
# Create a duplicate of the original xaxis, giving you an additional axis object
ax1 = ax.twinx()
# Set the limits of the new axis from the original axis limits
ax1.set_ylim(ax0.get_ylim())
This will exactly duplicate the original y-axis.
Eg:
ax = plt.gca()
plt.bar(range(3), range(1, 4))
plt.axhline(1.75, color="gray", ls=":")
twin_ax = ax.twinx()
twin_ax.set_yticks([1.75])
twin_ax.set_ylim(ax.get_ylim())