How to draw a line on a plot? - python-3.x

I am trying to draw a line on a plit, but the plot is not even showing.
I have checked the values of xPoints and yPoints and they exist.
What is the cause?
import matplotlib.pyplot as plt
import numpy as np
def calculateFuncFor(x):
ePower = np.e**np.exp(x)
result = 1 - ePower
return "{:.4f}".format(result) #format the result
xPoints = np.linspace(0,1) #outputs 50 points between 0 and 1
yPoints = np.zeros(len(xPoints)) #fill a list with 50 zeros
for i in range(len(xPoints)):
yPoints[i] = calculateFuncFor(xPoints[i])
plt.plot(xPoints, yPoints,'ro')
plt.show()

Try putting in the first cell of your Jupyter Notebook the following:
%matplotlib inline
% denotes the IPython magic built-in commands

Related

How do I format as latex an element of an array into a title/label in Python?

I have an array of numbers and I want its elements as the titles of subplots in a figure in Python. I want to format these titles in latex style.
I'm afraid this might be a simple question but I have not seen the answer elsewhere. I've seen that people use raw strings r'$ ... $' for latex expressions but I could not apply it successfully to solve this problem.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rc
#LaTeX font
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
rc('text', usetex=True)
# Some example data to display
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
#The numbers I want as titles for the subplots
Nums = [0.01,0.10,0.30,0.75,1.00,2.00,10.0,12.0]
nrows=2
ncols=4
fig, ax = plt.subplots(nrows=2,ncols=4)
for row in range(nrows):
for col in range(ncols):
ax[row,col].set_title(repr(Nums[col+row*ncols]) + '$\\ \\mathrm{GeV}$')
ax[row,col].plot(x, y)
plt.show()
The best I managed to do is write the units in latex style and the numbers in "text" style. This is how it looks.
What do you say about that?
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rc
#LaTeX font
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
rc('text', usetex=True)
# Some example data to display
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
#The numbers I want as titles for the subplots
Nums = [0.01,0.10,0.30,0.75,1.00,2.00,10.0,12.0]
nrows=2
ncols=4
fig, ax = plt.subplots(nrows=2,ncols=4)
for row in range(nrows):
for col in range(ncols):
#ax[row,col].set_title(repr(Nums[col+row*ncols]) + '$\\ \\mathrm{GeV}$')
ax[row,col].set_title(r'${:.2f}\mathrm{{GeV}}$'.format(Nums[col+row*ncols]))
ax[row,col].plot(x, y)
plt.show()
giving you this output
In you solution you juste encoded the GeV part as laTex, while the number was encoded as plain test (not in dollars).
You find more info about the used format statement here.
Note: You should replace Nums with nums. Capitalized variables are used for classes. Read the PEP8 Style guide for more info.

NaN values as special color in pyplot scatter plot

I have an (x,y)-scatter plot, where each point is associated with a color. Some points, however, do not have a valid color, and are assigned NaN. I would like to include these points, but show them in a color not contained by the colormap.
Here's the example code:
import numpy as np
import matplotlib.colors as mcol
import matplotlib.pyplot as plt
numPoints = 20
nanFrequency = 3
xVec = np.arange(numPoints, dtype=float)
yVec = xVec
colorVec = np.linspace(0,1,numPoints)
colorVec[range(0, numPoints, nanFrequency)] = np.nan
colormap = mcol.LinearSegmentedColormap.from_list("Blue-Red-Colormap", ["b", "r"])
plt.scatter(xVec, yVec, c=colorVec, cmap=colormap)
and the corresponding output:
Every third point is not shown due to its invalid color value. Based on my code, I would have expected these points to be shown in yellow. Why doesn't this work?
Note that there's a related post concerning imshow(), from which the above code is inspired. The solution presented there does not seem to work for me.
Many thanks in advance.
Of course you need to set the desired yellow to your colormap, colormap.set_bad("yellow").
Then, this is a long standing bug in matplotlib (#4354), which fortunately has now been fixed (#12422).
So from matplotlib 3.1 onwards, you can use the plotnonfinite=True argument to include masked or invalid points in scatter plots.
import numpy as np
import matplotlib.colors as mcol
import matplotlib.pyplot as plt
numPoints = 20
nanFrequency = 3
xVec = np.arange(numPoints, dtype=float)
yVec = xVec
colorVec = np.linspace(0,1,numPoints)
colorVec[range(0, numPoints, nanFrequency)] = np.nan
colormap = mcol.LinearSegmentedColormap.from_list("Blue-Red-Colormap", ["b", "r"])
colormap.set_bad("yellow")
plt.scatter(xVec, yVec, c=colorVec, cmap=colormap, plotnonfinite=True)
plt.show()
The reason that your NaN values are not plotted is that matplotlib's scatter currently filters them out before giving them to the colormap.
To show the NaN entries you can manually assign them a dummy value with a special meaning. For example, because your list is in the range [0, 1] you could define that any value > 1 get a special color. For this you will have to fix the range of the color-axis, and specify a color for entries outside this range (in this case higher than the maximum).
Basically you will use:
cax = ax.scatter(...)
cax.cmap.set_over('y') # assigns yellow to any entry >1
cax.set_clim(0, 1) # fixes the range of 'normal' colors to (0, 1)
For your example:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
numPoints = 20
nanFrequency = 3
xVec = np.arange(numPoints, dtype=float)
yVec = xVec
colorVec = np.linspace(0,1,numPoints)
colorVec[range(0, numPoints, nanFrequency)] = np.NaN
cmap = mpl.colors.LinearSegmentedColormap.from_list("Blue-Red-Colormap", ["b", "r"], numPoints)
# ---
fig, axes = plt.subplots(nrows=2, figsize=(8, 2*6))
# ---
ax = axes[0]
ax.scatter(xVec, yVec, c=colorVec, cmap=cmap)
ax.set_xlim([0, 20])
ax.set_ylim([0, 20])
# ---
ax = axes[1]
colorVec[np.isnan(colorVec)] = 2.0
cax = ax.scatter(xVec, yVec, c=colorVec, cmap=cmap)
cax.cmap.set_over('y')
cax.set_clim(0, 1)
ax.set_xlim([0, 20])
ax.set_ylim([0, 20])
# ---
plt.show()
Which produces two subplots: the top corresponds to what you had, the bottom uses the dummy value and assigns yellow to it:

setting manual x-axis ticks violin plot

I'm trying to build a violin plot using matplotlib.
While setting the manual X-axis ticks based on the example provided here, I am failing to do so. Where am I missing out?
Here is a MWE
#!/usr/bin/env python3
import os
import numpy as np
import warnings
import matplotlib.pyplot as plt
import matplotlib.cbook
import matplotlib as mpl
warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation)
OUTPUT_PATH=os.getcwd() + "/"
# Dots per inch for figure.
DPI = 500
def test_plot():
fig = plt.figure()
vector_size=100
bucket2 = np.random.rand(vector_size)
bucket3 = np.random.rand(vector_size)
bucket4 = np.random.rand(vector_size)
bucket5 = np.random.rand(vector_size)
bucket6 = np.random.rand(vector_size)
pos = [1,2,3,4,5]
data= [np.array(bucket2), np.array(bucket3), np.array(bucket4), np.array(bucket5), np.array(bucket6)]
axes1 = fig.add_subplot(111)
axes1.violinplot(data, pos, points=100, widths=0.7, showmeans=False, showextrema=True, showmedians=True)
axes1.set_xlabel('x-axis')
axes1.set_ylabel('y-axis')
xticks_t = ["",".1-.2", ".2-.3", ".3-.4", ".4-.5", ">.5"]
axes1.set_xticklabels(xticks_t)
axes1.set_xlim([0, 5])
axes1.spines['right'].set_visible(False)
axes1.spines['top'].set_visible(False)
axes1.xaxis.set_ticks_position('bottom')
axes1.yaxis.set_ticks_position('left')
fig.tight_layout()
file_name = 'test_violin.pdf'
fig.savefig(OUTPUT_PATH + str(file_name), bbox_inches='tight', dpi=DPI, pad_inches=0.1)
fig.clf()
plt.close()
pass
test_plot()
You can use the LaTeX expressions for the last tick to correctly display > as
xticks_t = ["",".1-.2", ".2-.3", ".3-.4", ".4-.5", r"$>.5$"]
and comment out the x-axis limits # axes1.set_xlim([0, 5])
which produces

Issue with drawparallels argument in Basemap

This seems like it should be an easy fix but I can't get it to work. I would like 40°N to display in the attached plot, but setting the labels argument in drawparallels to [1,0,1,1] isn't doing the trick. That should plot the parallels lables where they intersect the left, top and bottom of the plot according to the documentation. I would also like for 0° to once again show up in the bottom right corner. Any idea of how I can fix those 2 issues?
from netCDF4 import Dataset as NetCDFFile
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap
from mpl_toolkits.basemap import addcyclic
nc = NetCDFFile('C:/myfile.nc')
lat = nc.variables['lat'][:]
lon = nc.variables['lon'][:]
time = nc.variables['time'][:]
olr = nc.variables['olr'][:]
olr,lon = addcyclic(olr,lon)
map = Basemap(llcrnrlon=0.,llcrnrlat=-40.,urcrnrlon=360.,urcrnrlat=40.,resolution='l')
lons,lats = np.meshgrid(lon,lat)
x,y = map(lons,lats)
levels = np.arange(-19.5,20.0,0.5)
levels = levels[levels!=0]
ticks = np.arange(-20.0,20.0,4.0)
cs = map.contourf(x,y,olr[0],levels, cmap='bwr')
cbar = plt.colorbar(cs, orientation='horizontal', cmap='bwr', spacing='proportional', ticks=ticks)
cbar.set_label('Outgoing Longwave Radiation Anomalies $\mathregular{(W/m^2)}$')
map.drawcoastlines()
map.drawparallels(np.arange(-40,40,20),labels=[1,0,1,1], linewidth=0.5, fontsize=7)
map.drawmeridians(np.arange(0,360,40),labels=[1,1,0,1], linewidth=0.5, fontsize=7)
The first part of the question is easy. In order for the label to show up, you have to actually draw the parallel, but np.arange(-40,40,20) does not include 40. So, if you change that statement to np.arange(-40,41,20) your 40N label will show up.
The second part should in principle be solvable in the same way, but Basemap apparently uses the modulo of the longitudes to compute the position of the labels, so just using np.arange(0,361,40) when drawing the meridians will result in two 0 labels on top of each other. However, we can capture the labels that drawmeridians generates and manually change the position of the second 0 label. The labels are stored in a dictionary, so they are easy to deal with. To compute the x position of the last label, I compute the difference in x-position between the first and the second label, multiply that with the amount of meridians to be drawn (360/40) and add the x-position of the first label.
Here the complete example:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap
map = Basemap(llcrnrlon=0.,llcrnrlat=-40.,urcrnrlon=360.,urcrnrlat=40.,resolution='l')
map.drawcoastlines()
yticks = map.drawparallels(
np.arange(-40,41,20),labels=[1,0,1,1], linewidth=0.5, fontsize=7
)
xticks = map.drawmeridians(
np.arange(0,361,40),labels=[1,1,0,1], linewidth=0.5, fontsize=7
)
first_pos = xticks[0][1][0].get_position()
second_pos = xticks[40][1][0].get_position()
last_x = first_pos[0]+(second_pos[0]-first_pos[0])*360/40
xticks[360][1][0].set_position((last_x,first_pos[1]))
plt.show()
Here the resulting plot:
Hope this helps.

python-'str' abject has no attribute 'scatter'

I need to plot a 7x7 scatterplot diagram by metplotlib.pyplot (no seaborn at this moment). I try to make it semi automatics, so I use an array of ax names ax11, ax12, ......, ax77 to present the subplots. mean while when I use them to call scatter, it is rejected, I think python recognize them as strings but not keywords for the subplot. The Error Message is "AttributeError: 'str' object has no attribute 'scatter'". Here is the part of the code:
import matplotlib.pyplot as plt
import numpy as np
characters = ['A','B','C','D','E','F']
box = dict(facecolor ='yellow', pad = 5, alpha = 0.2)
fig, ((ax11,ax12,ax13,ax14,ax15,ax16,ax17),\
(ax21,ax22,ax23,ax24,ax25,ax26,ax27),\
(ax31,ax32,ax33,ax34,ax35,ax36,ax37),\
(ax41,ax42,ax43,ax44,ax45,ax46,ax47),\
(ax51,ax52,ax53,ax54,ax55,ax56,ax57),\
(ax61,ax62,ax63,ax64,ax65,ax66,ax67),\
(ax71,ax72,ax73,ax74,ax75,ax76,ax77),\
) = plt.subplots(7,7)
fig.subplots_adjust(left = 0.2, wspace =0.2,)
fig.tight_layout(pad=1, w_pad=2, h_pad=4.0)
st = fig.suptitle("Scatterplot diagram", \
fontsize="x- large")
for i in range(7):
for j in range(7):
no_ax = str(i)+str(j)
nm_ax = "ax"+str(no_ax)
nm_ax.scatter(data[caracters[i]],data[caracters[i]])
nm_ax.set_title('xy')
nm_ax.set_xlabel('x')
nm_ax.set_ylabel('y')
continue
st.set_y(0.95)
fig.subplots_adjust(top=0.85)
plt.show()
I believe there is a method to convert the string to a right format, but I do not know how. Please help. Thanks.
In general the approach of building variable names from strings should be avoided. While this can be done using the eval function, it's not even necessary.
The problem lies in the lines
no_ax = str(i)+str(j) #this is a string
nm_ax = "ax"+str(no_ax) # this is still a string
nm_ax.scatter(data[caracters[i]],data[caracters[i]])
# a string cannot be plotted to
A string does not have a scatter method. What you need is the axes object to which you plot.
A solution is to just use the axes that are created in the call to plt.subplots()directly in the loop.
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(ncols=7,nrows=7)
for i in range(7):
for j in range(7):
axes[i,j].scatter(np.random.rand(5),np.random.rand(5))
axes[i,j].set_title('{},{}'.format(i,j))
plt.show()

Resources