All, I am pretty new to matplotlib.
How could I change the font.weight when using [text.usetex]:
In the following code, I am using a greek symbol (lambda) for the xaxis but the weight of the symbol itself seems to be light and is poorly noticeable when a pdf file is produced from the latex file.
I don't understand why setting font.weight='bold' doesn't have an effect.
Any idea how could I change the weight of the {lambda} symbol. Please, NOTE: I don't mean to change the font size but the font weight.
Thank you in advance!
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.gridspec as gridspec
from list2nparr import list2nparr
plt.rcParams['text.latex.preamble']=[r"\usepackage{lmodern}"]
plt.rcParams['text.usetex'] = True
plt.rcParams['font.family'] = 'lmodern'
plt.rcParams['font.weight'] = 'bold'
fig = plt.figure()
for j in range(1,5):
l = str(j)
ax = fig.add_subplot(2,2,j)
data = list2nparr('pwq'+l+'.txt')
data2 = list2nparr('ssflux.dat')
x = data[:,0]
y1 = data[:,1]
y2 = data[:,2]
y3 = data[:,3]
y4 = data[:,4]
mxval = []
for i in range(len(x)):
c= data[i,1]+data[i,2]+data[i,3]+data[i,4]
mxval.append(c)
fact = 26*max(mxval)
xc = data2[:,0]
yc = data2[:,1]
yer = data2[:,2]
ax.bar(x,y1, 1.6666, color='#FFA500',lw = 0.5)
ax.bar(x,y2, 1.6666, color='#00BFFF',bottom = y1,lw=0.5)
ax.bar(x,y3, 1.6666, color='m',bottom = y2+y1, lw=0.5)
ax.bar(x,y4, 1.6666, color='g',bottom = y3+y2+y1,lw = 0.5)
ax.errorbar(xc,yc*fact,yerr=yer*fact,fmt='o',c='k',mec='k',lw = 0.2, ms=2.5)
plt.ylim(ymin=0)
ax.tick_params(axis='both', labelsize=16)
ax.ticklabel_format(style='sci',scilimits=(-3,4),axis='both',labelsize=17)
# ax.yaxis.major.formatter._useMathText = True
if j == 1 or j == 2:
ax.axes.xaxis.set_ticklabels([])
if j == 1 or j == 3:
plt.ylabel('N',rotation = 0,labelpad=20)
if j == 3 or j == 4:
plt.xlabel(r"$\lambda_{\odot}$, (deg)", fontsize=17,fontweight='bold')
plt.subplots_adjust(hspace=0.12)
plt.savefig('figure.eps', fmt = 'eps',bbox_inches='tight')
Related
How to set xlim and ylim to see both cureves (omega and y) on a plot? Or how to verify that it is not possible?
import matplotlib.pyplot as plt
import numpy as np
e = 1.602176634e-19
m_e = 9.1093837015e-31
k = np.arange(0.00001, 50000, 0.003)
eps_0 = 8.8541878128e-12
n_0 = 100
c = 299792458
omega_p = np.sqrt(n_0*e**2/(eps_0*m_e))
omega = np.sqrt(omega_p**2+c**2+k**2)
y = k*c
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [5, 5]
# Plot
ax.yaxis.set_label_coords(-0.07, 0.84)
ax.xaxis.set_label_coords(0.95, -0.05)
ax.set_xlabel(r'$k$')
ax.set_ylabel(r'$\omega$', rotation='horizontal')
ax.set_xlim(10000, 40000)
ax.set_ylim(299792454, 299792462.1700816)
ax.plot(k, omega)
ax.plot(k, y)
# Focusing on appropriate part
print(omega[1000000]-omega[999999])
print(omega[-1]-omega[-2])
print(len(omega))
print(k[1000000])
print(k[-1])
print(omega[1000000])
print(omega[-1])
print(y[int(ax.get_xlim()[0])])
print(y[int(ax.get_xlim()[1])])
plt.show()
The output now:
There should be also an assymptote.
An idea is to just let matplotlib choose its default limits. Then you can interactively zoom in to an area of interest. The code below sets a log scale for the y-axis, which might help to fit everything. In order to avoid too many points, the 16 million points of np.arange(0.00001, 50000, 0.003) are replaced by np.linspace(0.00001, 50000, 10000).
import matplotlib.pyplot as plt
import numpy as np
e = 1.602176634e-19
m_e = 9.1093837015e-31
# k = np.arange(0.00001, 50000, 0.003)
k = np.linspace(0.00001, 50000, 10000)
eps_0 = 8.8541878128e-12
n_0 = 100
c = 299792458
omega_p = np.sqrt(n_0 * e ** 2 / (eps_0 * m_e))
omega = np.sqrt(omega_p ** 2 + c ** 2 + k ** 2)
y = k * c
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [5, 5]
ax.set_xlabel(r'$k$')
ax.set_ylabel(r'$\omega$', rotation='horizontal')
ax.plot(k, omega, color='blue')
ax.plot(k, y, color='red')
ax.set_yscale('log')
plt.show()
Right now there're some statistics plotted in 3d bar over (x, y). each bar height represents the density of the points in side the square grid of (x,y) plane. Right now, i can put different color on each bar. However, I want to put progressive color on the 3d bar, similar as the cmap, so the bar will be gradient filled depending on the density.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# height of the bars
z = np.ones((4, 4)) * np.arange(4)
# position of the bars
xpos, ypos = np.meshgrid(np.arange(4), np.arange(4))
xpos = xpos.flatten('F')
ypos = ypos.flatten('F')
zpos = np.zeros_like(xpos)
dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = z.flatten()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average')
plt.show()
Output the above code:
Let me first say that matplotlib may not be the tool of choice when it comes to sophisticated 3D plots.
That said, there is no built-in method to produce bar plots with differing colors over the extend of the bar.
We therefore need to mimic the bar somehow. A possible solution can be found below. Here, we use a plot_surface plot to create a bar that contains a gradient.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection= Axes3D.name)
def make_bar(ax, x0=0, y0=0, width = 0.5, height=1 , cmap="viridis",
norm=matplotlib.colors.Normalize(vmin=0, vmax=1), **kwargs ):
# Make data
u = np.linspace(0, 2*np.pi, 4+1)+np.pi/4.
v_ = np.linspace(np.pi/4., 3./4*np.pi, 100)
v = np.linspace(0, np.pi, len(v_)+2 )
v[0] = 0 ; v[-1] = np.pi; v[1:-1] = v_
x = np.outer(np.cos(u), np.sin(v))
y = np.outer(np.sin(u), np.sin(v))
z = np.outer(np.ones(np.size(u)), np.cos(v))
xthr = np.sin(np.pi/4.)**2 ; zthr = np.sin(np.pi/4.)
x[x > xthr] = xthr; x[x < -xthr] = -xthr
y[y > xthr] = xthr; y[y < -xthr] = -xthr
z[z > zthr] = zthr ; z[z < -zthr] = -zthr
x *= 1./xthr*width; y *= 1./xthr*width
z += zthr
z *= height/(2.*zthr)
#translate
x += x0; y += y0
#plot
ax.plot_surface(x, y, z, cmap=cmap, norm=norm, **kwargs)
def make_bars(ax, x, y, height, width=1):
widths = np.array(width)*np.ones_like(x)
x = np.array(x).flatten()
y = np.array(y).flatten()
h = np.array(height).flatten()
w = np.array(widths).flatten()
norm = matplotlib.colors.Normalize(vmin=0, vmax=h.max())
for i in range(len(x.flatten())):
make_bar(ax, x0=x[i], y0=y[i], width = w[i] , height=h[i], norm=norm)
X, Y = np.meshgrid([1,2,3], [2,3,4])
Z = np.sin(X*Y)+1.5
make_bars(ax, X,Y,Z, width=0.2, )
plt.show()
I know the question is not very informative.. but as I do not know the name of his type of plot, I can not be more informative..
[EDIT] I changed the title, and now it is more informative...
You can do something similar with seaborn.swarmplot. I also use seaborn.boxplot (with the whiskers and caps turned off) to plot the mean and range:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
tips = sns.load_dataset("tips")
ax = sns.swarmplot(x="day", y="total_bill", data=tips)
ax = sns.boxplot(x="day", y="total_bill", data=tips,
showcaps=False,boxprops={'facecolor':'None'},
showfliers=False,whiskerprops={'linewidth':0})
plt.show()
If (for whatever reason) you don't want to use seaborn, you can have a go at making them yourself (see e.g. this explanation: https://www.flerlagetwins.com/2020/11/beeswarm.html ).
A simple version is:
#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as np
def simple_beeswarm(y, nbins=None):
"""
Returns x coordinates for the points in ``y``, so that plotting ``x`` and
``y`` results in a bee swarm plot.
"""
y = np.asarray(y)
if nbins is None:
nbins = len(y) // 6
# Get upper bounds of bins
x = np.zeros(len(y))
ylo = np.min(y)
yhi = np.max(y)
dy = (yhi - ylo) / nbins
ybins = np.linspace(ylo + dy, yhi - dy, nbins - 1)
# Divide indices into bins
i = np.arange(len(y))
ibs = [0] * nbins
ybs = [0] * nbins
nmax = 0
for j, ybin in enumerate(ybins):
f = y <= ybin
ibs[j], ybs[j] = i[f], y[f]
nmax = max(nmax, len(ibs[j]))
f = ~f
i, y = i[f], y[f]
ibs[-1], ybs[-1] = i, y
nmax = max(nmax, len(ibs[-1]))
# Assign x indices
dx = 1 / (nmax // 2)
for i, y in zip(ibs, ybs):
if len(i) > 1:
j = len(i) % 2
i = i[np.argsort(y)]
a = i[j::2]
b = i[j+1::2]
x[a] = (0.5 + j / 3 + np.arange(len(b))) * dx
x[b] = (0.5 + j / 3 + np.arange(len(b))) * -dx
return x
fig = plt.figure(figsize=(2, 4))
fig.subplots_adjust(0.2, 0.1, 0.98, 0.99)
ax = fig.add_subplot(1, 1, 1)
y = np.random.gamma(20, 10, 100)
x = simple_beeswarm(y)
ax.plot(x, y, 'o')
fig.savefig('bee.png')
I based my heatmap off of: Heatmap in matplotlib with pcolor?
I checked out How to change separation between tick labels and axis labels in Matplotlib but it wasn't what I needed
How do I fix the positions of the labels so they align with the ticks?
#!/usr/bin/python
import matplotlib.pyplot as plt
import numpy as np
import random
in_path = '/path/to/data'
in_file = open(in_path,'r').read().split('\r')
wd = '/'.join(in_path.split('/')[:-1]) + '/'
column_labels = [str(random.random()) + '_dsiu' for i in in_file[0].split('\t')[2:]]
row_labels = []
#Organize data for matrix population
D_cyano_counts = {}
for line in in_file[2:]:
t = line.split('\t')
D_cyano_counts[(t[0],t[1])] = [int(x) for x in t[2:]]
#Populate matrix
matrix = []
for entry in sorted(D_cyano_counts.items(), key = lambda x: (np.mean([int(bool(y)) for y in x[-1]]), np.mean(x[-1]))):#, np.mean(x[-1]))):
(taxon_id,cyano), counts = entry
normalized_counts = []
for i,j in zip([int(bool(y)) for y in counts], counts):
if i > 0:
normalized_counts.append(i * (5 + np.log(j)))
else:
normalized_counts.append(0)
#Labels
label_type = 'species'
if label_type == 'species': label = cyano
if label_type == 'taxon_id': label = taxon_id
row_labels.append(str(random.random()))
#Fill in matrix
matrix.append(normalized_counts)
matrix = np.array(matrix)
#Fig
fig, ax = plt.subplots()
heatmap = ax.pcolor(matrix, cmap=plt.cm.Greens, alpha = 0.7)
#Format
fig = plt.gcf()
#
ax.set_frame_on(False)
#
font = {'size':3}
ax.xaxis.tick_top()
ax.set_xticks([i + 0.5 for i in range(len(column_labels))])
ax.set_yticks([i + 0.5 for i in range(len(row_labels))])
ax.set_xticklabels(column_labels, rotation = (45), fontsize = 10, va='bottom')#, fontweight = 'demi')
ax.set_yticklabels(row_labels, fontsize = 9, fontstyle='italic')
cbar = plt.colorbar(heatmap)
help(ax.set_xticklabels)
ax.margins(x=0.01,y=0.01)
fig.set_size_inches(20, 13)
plt.savefig('figure.png')
you have to set the horizontal alignment of the labels to left in your case. They are centered by default.
The link from #Jean-Sébastien contains your answer
ax.set_xticklabels(column_labels, rotation = (45), fontsize = 10, va='bottom', ha='left')
I have a problem with PolyCollection matplotlib when I work with python 2.5. In random mode, it shows me following error: array dimensions must agree except for d_0 (file:collection.py - xy = np.concatenate([xy, np.zeros((1,2))])). This is my code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.font_manager as fm
from matplotlib.patches import Rectangle
import matplotlib.cm as cm
colors = ['#be1e2d',
'#666699',
'#92d5ea',
'#ee8310',
'#8d10ee',
'#5a3b16',
'#26a4ed',
'#f45a90',
'#e9e744']
row_names = ['2005','2006','2007']
data = [[1,1,1,1,1,1],[2,2,2,2,2,2],[4,4,4,4,4,4],[5,5,5,5,5,5],[7,7,7,7,7,7],[8,8,8,8,8,8]]
column_names = ['Ri','Pe']
#0 to start and end list
i=0
for i in range(len(data)):
data[i].append(0)
for i in range(len(data)):
data[i].insert(0,0)
dpi = 50.0
width = 460
height = 440
fig = plt.figure(1, figsize=(width/dpi,height/dpi),facecolor='w')
ax = fig.gca(projection='3d')#,azim=40, elev=0)
#Build axes
size = len(row_names) * len(data[0])
zs = np.arange(len(data))
# Setto le properties dei font
fp = fm.FontProperties()
fp.set_size('xx-small')
#Build Graph
verts = []
step = 1.0/len(data[0])
vertsColor = []
#Verify Single series or not
if len(column_names) > 1:
idx = 0
xs = np.arange(0, size, step)
change_color = len(column_names) - 1
for z in zs:
verts.append(zip(xs, data[z]))
vertsColor.append(colors[idx])
if idx == change_color:
idx = 0
else:
idx = idx + 1
################################################
# I THINK THE PROBLEM IS HERE
poly = PolyCollection(verts,facecolors=vertsColor)
ax.add_collection3d(poly, zs=zs, zdir='y')
################################################
ax.set_ylim3d(0, len(row_names)*len(column_names))
zs = np.arange(0,len(row_names) * len(column_names), len(column_names))
ax.set_yticks(zs)
lim = ((size*step)-step) - (len(row_names) - 1)
ax.set_xlim3d(0, lim)
rect = []
serie = []
#Build legend
for i in range(len(column_names)):
rect.insert(i,Rectangle((0,0), 1,1, facecolor=colors[i]))
serie.insert(i,column_names[i])
ax.legend((rect), (serie), loc=3, ncol=3, prop=fp)
else:
xs = np.arange(0, size, step)
for z in zs:
verts.append(zip(xs, data[z]))
poly = PolyCollection(verts,facecolors=colors) #[:len(data)])
poly.set_alpha(0.6)
ax.add_collection3d(poly, zs=zs, zdir='y')
ax.set_xlabel('Rec')
lim = ((size*step)-step) - (len(row_names) - 1)
ax.set_xlim3d(0, lim)
ax.set_yticks(zs)
ax.set_ylim3d(0, len(row_names))
#Find Max Value
max_value = 0
i=0
for i in data:
mass = max(i)
if mass > max_value:
max_value = mass
#Font Label X,Y,Z
for label in ax.get_xticklabels():
label.set_fontproperties(fp)
for label in ax.get_yticklabels():
label.set_fontproperties(fp)
for label in ax.get_zticklabels():
label.set_fontproperties(fp)
ax.set_xticklabels('')
ax.set_ylabel('Years')
ax.set_yticklabels(row_names, fontproperties = fp)
ax.set_zlabel('Values')
ax.set_zlim3d(0, max_value)
ax.set_title('Test',x=0.5, y=1)
plt.show()
THANKS.