I would like to create a plot where some of the points have a downward pointing arrow (see image below). In Astronomy this illustrates that the true value is actually lower than what's measured.Note that only some of the points have this symbol.
I would like to know how I can create such symbols in matplotlib. Are there downward arrow symbols that I can use?
Thanks for your help in advance!
Sure.
When calling matplotlibs plot function, set a marker
If stuff like caretdown doesn't work for you, you can create your own marker by passing a list of (x,y) pairs, which are passed to a Path artist. x/y are 0…1 normalized coordinates that are scaled to the set marker size.
You can also pass an existing Path instance as a marker, which allows even more flexibility.
As mentioned by tom10 in the comments you can also pass a string in the form of $…$ as a marker, where … is arbitrary text, including Unicode characters, if your font supports it (should be the case these days). Downwards arrow in Unicode: ↓ (or \u2193, resulting in $\u2193$ as the marker. Note that this must be a unicode string in Python 2.x [prepend u]). Unicode Block Arrows # Wikipedia
You could also try passing a Arrow instance as marker, but I'm not sure whether that works.
The answer to my question was answered by Tom0 and Dom0. However, I just want to help the newbies like me understand how to plot those arrows. Below is the code that I found and edited to include what is said in the above example and suggestion. I hope this will help people quickly understand. I am not seeking any points.
If you like the example, please thank Dom0 and not me. :-)
import numpy as np
import matplotlib.pyplot as plt
symbols = [u'\u2193'] # this helps you get the symbol
x = np.arange(10.)
y = np.exp(-x/2.)
plt.figure()
for i, symbol in enumerate(symbols):
y2 = np.exp(-x/2.)
plt.plot(x, y, 'o') # plotting with field circles
plt.plot(x, y2, 'g') # plotting with green line
for x0, y0 in zip(x, y2):
plt.text(x0, y0, symbol, fontname='STIXGeneral', size=30, va='center', ha='center', clip_on=True)
plt.show()
Matplotlib supports a subset of Latex in a built-in module called mathtext. The main purpose is to properly render mathematical and scientific equations and symbols, but there's also large number of arrow symbols that can easily be used in your graphs. The following link is to the tutorial for writing math expressions. Near the bottom of the page is a list of about 80 arrow symbols.
https://matplotlib.org/users/mathtext.html#mathtext-tutorial
Examples:
plt.plot(x, y, marker=r'$\uparrow$')
plt.plot(x, y, marker=r'$\downarrow$')
Take a look at this example code: http://matplotlib.org/examples/pylab_examples/errorbar_limits.html
OR:
Another easy way to do this:
arrow = u'$\u2193$'
ax.plot(x, y, linestyle='none', marker=arrow, markersize=10)
Related
I want to plot some impedance values and task and code are both simple. xhertz_df is a pandas dataframe and after conversion to a numpy array xhertz[0]is the real part, xhertz[1]the imaginary part and xhertz[3]represents the time between measurements.
def xhertz_plot(xhertz_df):
ax = plt.gca()
xhertz = xhertz_df.T.to_numpy()
ax.plot(xhertz[3], xhertz[0], 'green')
ax.plot(xhertz[3], xhertz[1], 'blue')
ax.scatter(xhertz[3], xhertz[0], cmap ='green')
ax.scatter(xhertz[3], xhertz[1], cmap ='blue')
ax.set_xlabel('Time Passed (in Minutes)')
plt.show()
I'm confused as to what can go wrong with this code as it seems so simple. Yet I get this result:
The upper line and points is a mix of blue and green even though it should be just green. The lower line that should be only blue has orange (?!) points. What is going on here?
Edit:
I found the problem: I used cmap instead of just c for the scatter plot. But to someone with expertise in both concepts: Why did I get the result shown above? E.g. where did the orange come from?
As stated in the docs for Axes.scatter:
A Colormap instance or registered colormap name. cmap is only used if c is an array of floats.
Since you did not provide a list of floats for the arg c, matplotlib ignored your cmap and instead used the first and second default colors (blue, then orange).
If you just want a single color, note the docs for the c argument:
If you wish to specify a single color for all points prefer the color keyword argument.
Alternatively, you can just use Axes.plot with o for the marker style, instead of scatter, e.g. ax.plot(x, y, 'o', color='green') or equivalently ax.plot(x, y, 'og'). This is more typical for simple plots; you can use - or o to explicitly set a line plot or marker plot.
Note that cmap is generally intended to be used if you want a different color for each point, like if you wanted to color the points to represent another dimension of data. In that case c would represent that third dimension of data, norm would scale the data, and cmap would be what colors are mapped to that data. See the scatter demo 2 from matplotlib for an example of how that argument is usually used.
I have a plot where the data points has been cut off, as can be seen in the picture. I need to fix this issue by showing clearly the data points, I have already tried to use ax.margins from previous questions , but it does not change anything on my plot. The following is the code I am using. I guess the ylim might be raising this issue, but if I don't use ylim all my data stays very near to zero axis.
def doscatterplot(xcoord,ycoord,labellist,ax=None):
ax = ax
ax.scatter(xcoord, ycoord,label=labellist)
# ax.xaxis.set_major_formatter(mtick.FormatStrFormatter('%.2f'))
ax.legend()
ax.margins(0.1,y=0.7)
ax.set_ylim(min(ycoord),max(ycoord))
ax.ticklabel_format(axis='y',style='sci',scilimits=(-3,-4))
ax.axhline(y=0, color='g')
ax.axvline(x=0, color='g')
ax.set_ylabel('Transversal Resistance [\u03A9]')
ax.set_xlabel('HCools [T]')
ax.set_title('Transversal Resistance [\u03A9] vs HCools [T]' )
return
What I meant in my comment is to add this extra line of code:
dy = (max(ycoord) - min(ycoord))/20
to add a little extra space above and below your plotted data (in this case, the 20th part of the range of your data). Change the old line for this one and it should work as you want:
ax.set_ylim(min(ycoord) - dy, max(ycoord) + dy)
Also, note that you can write greek symbols without resorting to unicode language, try for example
ax.set_ylabel(r'Transversal Resistance [$\Omega$]')
You can see more information here.
I have to plot some data and some vertical lines to delimit interesting intervals and then I would like to add some labels to that using text. I can not entirely avoid the labels overlapping with the data or the vertical lines, so I decided to put a bbox around the text to keep it readable. My problem is that I am not able to align it centrally within this box and this is clearly visible and quite annoying in my opinion.
I'm doing something like this:
import numpy
import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()
plot=fig.add_subplot(111)
x=numpy.linspace(1,10,50)
y=numpy.random.random(50)
plot.plot(x,y)
plot.text(4.5,.5,'TEST TEST',\
bbox={'facecolor':'white','alpha':1,'edgecolor':'none','pad':1})
plot.axvline(5,color='k',linestyle='solid')
plt.show()
Which creates the following plot:
It is quite apparent, that the text is not centered in its bbox. How can I change this? I've spent quite some time on Google but I could not find anything.
EDIT:
Thanks for the suggestions so far.
This suggests that what I see is actually desired behavior. Apparently the bbox in new versions of matplotlib is chosen taking into account the possible maximum descent of the text it contains (the descent of 'g').
When a 'g' appears in the text, this does indeed look good:
Unfortunately in my case there is no 'g' or anything with a similar descent. Does anyone have any further ideas?
Use the text properties ha and va:
plot.text(5.5,.5,'TEST TEST TEST TEST',
bbox={'facecolor':'white','alpha':1,'edgecolor':'none','pad':1},
ha='center', va='center')
To check, draw lines in the center of your plot:
plot.axvline(5.5,color='k',linestyle='solid')
plot.axhline(0.5,color='k',linestyle='solid')
It seems that there are now options to properly position the text in the coordinate system (in particular the new va = 'baseline'). However, as pointed out by user35915, this does not change the alignment of the box relative to the text. The misalignment is particularly obvious in single digit numbers, in particular number '1' (see also this bug). Until this is fixed, my workaround is to place the rectangle by hand, not via the bbox parameter:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# define the rectangle size and the offset correction
rect_w = 0.2
rect_h = 0.2
rect_x_offset = 0.004
rect_y_offset =0.006
# text coordinates and content
x_text = 0.5
y_text = 0.5
text = '1'
# create the canvas
fig,ax = plt.subplots(figsize=(1,1),dpi=120)
ax.set_xlim((0,1))
ax.set_ylim((0,1))
# place the text
ax.text(x_text, y_text, text, ha="center", va="center", zorder=10)
# compare: vertical alignment with bbox-command: box is too low.
ax.text(x_text+0.3, y_text, text, ha="center", va="center",
bbox=dict(facecolor='wheat',boxstyle='square',edgecolor='black',pad=0.1), zorder=10)
# compare: horizontal alignment with bbox-command: box is too much to the left.
ax.text(x_text, y_text+0.3, text, ha="center", va="center",
bbox=dict(facecolor='wheat',boxstyle='square',edgecolor='black',pad=0.2), zorder=10)
# create the rectangle (below the text, hence the smaller zorder)
rect = patches.Rectangle((x_text-rect_w/2+rect_x_offset, y_text-rect_h/2+rect_y_offset),
rect_w,rect_h,linewidth=1,edgecolor='black',facecolor='white',zorder=9)
# add rectangle to plot
ax.add_patch(rect)
# show figure
fig.show()
I have this piece of code:
fig,ax=subplots(figsize=(20,10))
#ax=plot(matriz[0],matriz[1],color='black',lw=0,marker='+',markersize=10)
#ax=plot(matriz[2],matriz[3],color='blue',lw=0,marker='o',markersize=10)
#show ()
def animate(i):
ax=plot((matt[i][0],matt[i][2]),(matt[i][1],matt[i][3]),lw=0,color='r-',marker='o',markersize=8)
return ax
anim=animation.FuncAnimation(fig,animate,frames=numlin, interval=1000,blit=True,repeat=0)
show()
I really don't have experience with matplotlib, but my boss asked me to paint (in each iteration) each point with a different color (i.e. point 1 in red, point 2 in blue and so on). I want to paint each point with a different color, but it should keep the same color in the next iteration.
How can I do this in matplotlib?
I think I see what you want to do and, yes, I think it is possible. First, I have set up some random data to simulate what I think you have in matt
from random import random as r
numlin=50
matt = []
for j in xrange(numlin):
matt.append([r()*20, r()*10,r()*20,r()*10])
Now, using your code as closely as possible, I think you want to do this (I've added an init() function, which just returns an empty list, otherwise your first set of points stays on the axis throughout):
from matplotlib.pyplot import plot, show, subplots
import matplotlib.animation as animation
fig,ax=subplots(figsize=(20,10))
ax.set_xlim([0,20])
ax.set_ylim([0,10])
def animate(i):
animlist = plot(matt[i][0],matt[i][1],'r',matt[i][2],matt[i][3],'b',marker='o',markersize=8)
return animlist
def init():
return []
anim=animation.FuncAnimation(fig,animate,frames=numlin,interval=1000,init_func=init,blit=True,repeat=0)
show()
How it works
Passing in sets of (x0,y0,c0, x1,y1,c1, x2,y2,c2 ... ) into plot() is valid where cx is a valid matplotlib colour format. They go before any named **kwargs like marker etc. It's described in the docs here.
An arbitrary number of x, y, fmt groups can be specified, as in:
a.plot(x1, y1, 'g^', x2, y2, 'g-')
Edit in response to OP comment
OP wanted to make this extensible to more sets of points, without simply appending them all as arguments to the plot function. Here is one way (altering the animate() function - the rest stays the same)
def animate(i):
#Make a tuple or list of (x0,y0,c0,x1,y1,c1,x2....)
newpoints = (matt[i][0],matt[i][1],'r',
matt[i][0],matt[i][3],'b',
matt[i][2],matt[i][3],'g',
matt[i][2],matt[i][1],'y')
# Use the * operator to expand the tuple / list
# of (x,y,c) triplets into arguments to pass to the
# plot function
animlist = plot(*newpoints,marker='o',markersize=8)
return animlist
How do I create a contour plot with a symlog (symmetrical log) scale for the contours. i.e. a log scale that shows both negative and positive values.
One possibility would be to work off of this example:
http://matplotlib.org/examples/pylab_examples/contourf_log.html
Which gives this recipe for a log scale:
from matplotlib import pyplot, ticker
cs = pyplot.contourf(X, Y, z, locator=ticker.LogLocator())
However, this doesn't allow for negative values. There is a ticker.SymmetricalLogLocator(), which may be the solution, but it doesn't seem to have much documentation.
EDIT:
To clarify (since requesting negative values on a log scale may sound nonsensical), what I want is the same as the "symlog" scale provided on matplotlib axes. The plot below, (taken from another stack exchange post), shows symlog on the x-axis. It is a "log" scale, but handles negative values in a way that is clear to the viewer.
I want the same sort of scaling, but for the colorscale on contour or contourf.
I stumbled across this thread trying to do the same thing, i.e plotting a large range of values in both the positive and negative direction. In addition I wanted to have a granularity as fine as in imshow.
It turns out you can have that using "ticker.MaxNLocator(nbins)" where nbins can be set high to have a fine granularity, e.g. set nbins to 100.
I also wanted to have a nice Latex style ticker formatting, for which I found a solution on StackOverflow a while ago.
I will just post this code snippet here from one of the classes it is part of so that anyone who might want can get the basic idea about how it's working. I use this solution to generate multiple plots as shown in the image below.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
# function for nice Latex style tick formatting
# copied from
# http://stackoverflow.com/questions/25983218/
# scientific-notation-colorbar-in-matplotlib
# output formating for colorbar in 2D plots
def fmt(x, pos):
a, b = '{:.2e}'.format(x).split('e')
b = int(b)
return r'${} \times 10^{{{}}}$'.format(a, b)
# A confourf function I use inside one of my classes
# mainly interesting are the "plot" and "cbar" lines
def Make2DSubPlot(self, posIdent, timeIdx,typeIdx):
plt.subplot(posIdent)
y = self.radPos
x = self.axPos
z = self.fieldList[timeIdx][typeIdx]
plot = plt.contourf(x, y, z, locator=ticker.MaxNLocator(100), \
aspect='auto',origin='lower')
cbar = plt.colorbar(plot, orientation='vertical', \
format=ticker.FuncFormatter(fmt))
cbar.ax.set_ylabel(self.labelList[typeIdx])
plt.xlabel(self.labelList[self.iax])
plt.ylabel(self.labelList[self.iax])