Matplotlib label y axis - python

I am trying to build a chart using matplotlib but unfortunately I cannot figure it out how to label the y axis. I want to do this starting from 0.1 to 1.0 with a 0.1 difference.
I managed to set its limits like this:
import numpy as np
import matplotlib.pyplot as plt
N = 10
menMeans = (0.58836, 0.6224, 0.73047, 0.79147, 0.79284, 0.79264, 0.79922, 0.82043, 0.81834, 0.74767)
ind = np.arange(N) # the x locations for the groups
width = 0.20 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind, menMeans, width, color='g')
womenMeans = (0.61139, 0.62270, 0.63627, 0.75868, 0.73087, 0.73128, 0.77205, 0.59866, 0.59385, 0.59891)
rects2 = ax.bar(ind+width, womenMeans, width, color='b')
# add some
ax.set_ylabel('Accuracy')
ax.set_xticks(ind+width)
ax.set_xticklabels( ('Naive', 'Norm', 'Unigrams \n(FreqDist)', 'Unigrams(LLR)', 'Unigrams (LLR)\n Bigrams', 'Unigrams (LLR)\n Bigrams (CHI)',
'Unigrams (LLR)\n Bigrams (LLR)', 'Features', 'POS', 'LDA') )
ax.legend( (rects1[0], rects2[0]), ('Naive Bayes', 'Maximum Entropy') )
ax.set_ylim(0, 1)
plt.grid(axis='y', linestyle='-')
plt.show()
but numbers on y axis show up only with a 0.2 difference. Any solution for this? Thank you!

Try this:
ax.set_ylim(0.1, 1)
import matplotlib.ticker as tick
ax.yaxis.set_major_locator(tick.MultipleLocator(0.1))

Related

Matplotlib, plot a vector of numbers as a rectangle filled with numbers

So let's say I have a vector of numbers.
np.random.randn(5).round(2).tolist()
[2.05, -1.57, 1.07, 1.37, 0.32]
I want a draw a rectangle that shows this elements as numbers in a rectangle.
Something like this:
Is there an easy way to do this in matplotlib?
A bit convoluted but you could take advantage of seaborn.heatmap, creating a white colormap:
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
data = np.random.randn(5).round(2).tolist()
linewidth = 2
ax = sns.heatmap([data], annot=True, cmap=LinearSegmentedColormap.from_list('', ['w', 'w'], N=1),
linewidths=linewidth, linecolor='black', square=True,
cbar=False, xticklabels=False, yticklabels=False)
plt.tight_layout()
plt.show()
In this case, the external lines won't be as thick as the internal ones. If needed, this can be fixed with:
ax.axhline(y=0, color='black', lw=linewidth*2)
ax.axhline(y=1, color='black', lw=linewidth*2)
ax.axvline(x=0, color='black', lw=linewidth*2)
ax.axvline(x=len(data), color='black', lw=linewidth*2)
Edit: avoid these lines and add clip_on=False to sns.heatmap (thanks/credit #JohanC)
Output:
We can add rectangles , and annotate them in a for loop.
from matplotlib import pyplot as plt
import numpy as np
# Our numbers
nums = np.random.randn(5).round(2).tolist()
# rectangle_size
rectangle_size = 2
# We want rectangles look squared, you can change if you want
plt.rcParams["figure.figsize"] = [rectangle_size * len(nums), rectangle_size]
plt.rcParams["figure.autolayout"] = True
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(len(nums)):
# We are adding rectangles
# You can change colors as you wish
plt.broken_barh([(rectangle_size * i, rectangle_size)], (0, rectangle_size), facecolors='white', edgecolor='black'
,linewidth = 1)
# We are calculating where to annotate numbers
cy = rectangle_size / 2.0
cx = rectangle_size * i + cy
# Annotation You can change color,font, etc ..
ax.annotate(str(nums[i]), (cx, cy), color='black', weight='bold', fontsize=20, ha='center', va='center')
# For squared look
plt.xlim([0, rectangle_size*len(nums)])
plt.ylim([0, rectangle_size])
# We dont want to show ticks
plt.axis('off')
plt.show()
One way using the Rectangle patch is:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle
x = np.random.randn(5).round(2).tolist()
fig, ax = plt.subplots(figsize=(9, 2)) # make figure
dx = 0.15 # edge size of box
buf = dx / 10 # buffer around edges
# set x and y limits
ax.set_xlim([0 - buf, len(x) * dx + buf])
ax.set_ylim([0 - buf, dx + buf])
# set axes as equal and turn off axis lines
ax.set_aspect("equal")
ax.axis("off")
# draw plot
for i in range(len(x)):
# create rectangle with linewidth=4
rect = Rectangle((dx * i, 0), dx, dx, facecolor="none", edgecolor="black", lw=4)
ax.add_patch(rect)
# get text position
x0, y0 = dx * i + dx / 2, dx / 2
# add text
ax.text(
x0, y0, f"{x[i]}", color="black", ha="center", va="center", fontsize=28, fontweight="bold"
)
fig.tight_layout()
fig.show()
which gives:

Matplotlib fill_between edge

I need to create a plot as close to this picture as possible (given the generated dataframe code below):
And here's the output plot of my code:
What I am having problems with is:
The edge of fill_between is not sharp as in the picture. What I have is some kind of white shadow. How do I change the line between the fillings to match a target picture?
How do I aling legend color lines to the center, but not to the left border which my code does?
Here's my code:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cm
import numpy as np
import pandas as pd
ncols = 10
figsize = (20, 5)
fontsize = 14
dti = pd.date_range('2013-01-01', '2020-12-31', freq='2W')
probabilities_in_time = np.random.random((ncols, len(dti)))
probabilities_in_time = probabilities_in_time / \
probabilities_in_time.sum(axis=0)
probabilities_in_time = pd.DataFrame(probabilities_in_time).T
probabilities_in_time.index = dti
cm_subsection = np.linspace(0, 1, ncols)
colors = [cm.coolwarm(x) for x in cm_subsection]
def plot_time_probabilities(probabilities_in_time, figsize):
plt.figure(figsize=figsize)
plt.yticks(np.arange(0, 1.2, 0.2), fontsize=fontsize)
plt.xticks(fontsize=fontsize)
draw_stack_plot(colors, probabilities_in_time)
set_grid()
set_legend()
plt.show()
def draw_stack_plot(colors, probabilities_in_time):
for i, color in enumerate(colors):
if i == 0:
plt.plot(probabilities_in_time[i], color=color)
plt.fill_between(probabilities_in_time.index,
probabilities_in_time[0], color=color)
else:
probabilities_in_time[i] += probabilities_in_time[i-1]
plt.fill_between(probabilities_in_time.index,
probabilities_in_time[i], probabilities_in_time[i-1],
color=color)
plt.plot(probabilities_in_time[i], label=' Probability: {}'.format(
i), color=color)
def set_grid():
ax = plt.gca()
ax.set_axisbelow(False)
ax.xaxis.grid(True, linestyle='-', lw=1)
def set_legend():
leg = plt.legend(loc='lower left', fontsize=14, handlelength=1.3)
for i in leg.legendHandles:
i.set_linewidth(12)
plot_time_probabilities(probabilities_in_time, figsize)
To set the legend in the center, you can set loc='center', or you can put the legend outside. To avoid that the legend handles grow to larger, you can leave out .set_linewidth(12) (this sets a very wide edge width of 12 points).
Shifting the colors by one position can help to show the fill borders more pronounced. To still have a correct legend, the label should then be added to fill_between.
The code below also tries to simplify part of the calls:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
import pandas as pd
ncols = 10
figsize = (20, 5)
fontsize = 14
dti = pd.date_range('2013-01-01', '2020-12-31', freq='2W')
probabilities_in_time = np.random.random((ncols, len(dti)))
probabilities_in_time = probabilities_in_time / probabilities_in_time.sum(axis=0)
probabilities_in_time = pd.DataFrame(probabilities_in_time).T
probabilities_in_time.index = dti
cm_subsection = np.linspace(0, 1, ncols)
colors = cm.coolwarm(cm_subsection)
def plot_time_probabilities(probabilities_in_time, figsize):
plt.figure(figsize=figsize)
plt.yticks(np.arange(0, 1.2, 0.2), fontsize=fontsize)
plt.xticks(fontsize=fontsize)
draw_stack_plot(colors, probabilities_in_time)
set_grid()
set_legend()
# plt.margins(x=0, y=0)
plt.margins(x=0.02)
plt.tight_layout()
plt.show()
def draw_stack_plot(colors, probabilities_in_time):
current_probabilities = 0
for i, color in enumerate(colors):
plt.fill_between(probabilities_in_time.index,
probabilities_in_time[i] + current_probabilities, current_probabilities,
color=color, label=f' Probability: {i}')
current_probabilities += probabilities_in_time[i]
plt.plot(current_probabilities,
color=colors[0] if i <= 1 else colors[-1] if i >= 8 else colors[i - 1] if i < 5 else colors[i + 1])
def set_grid():
ax = plt.gca()
ax.set_axisbelow(False)
ax.xaxis.grid(True, linestyle='-', lw=1)
def set_legend():
leg = plt.legend(loc='lower left', fontsize=14, handlelength=1.3)
# leg = plt.legend(loc='upper left', bbox_to_anchor=(1.01, 1), fontsize=14, handlelength=1.3)
# for i in leg.legendHandles:
# i.set_linewidth(12)
plot_time_probabilities(probabilities_in_time, figsize)

How to limit lower error of bar plot to 0?

I calculated the rttMeans and rttStds arrays. However, the value of rttStds makes the lower error less than 0.
rttStds = [3.330311915835426, 3.3189677330174883, 3.3319538853150386, 3.325173772304221, 3.3374145232695813]
How to set lower error to 0 instead of -#?
The python bar plot code is bellow.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(rc={'figure.figsize':(18,16)},style='ticks',font_scale = 1.5,font='serif')
N = 5
ind = ['RSU1', 'RSU2', 'RSU3', 'RSU4', 'RSU5'] # the x locations for the groups
width = 0.4 # the width of the bars: can also be len(x) sequence
fig = plt.figure(figsize=(10,6))
ax = fig.add_subplot(111)
p1 = plt.bar(ind, rttMeans, width, yerr=rttStds, log=False, capsize = 16, color='green', hatch="/", error_kw=dict(elinewidth=3,ecolor='black'))
plt.margins(0.01, 0)
#Optional code - Make plot look nicer
plt.xticks(rotation=0)
i=0.18
for row in rttMeans:
plt.text(i, row, "{0:.1f}".format(row), color='black', ha="center")
i = i + 1
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
params = {'axes.titlesize':24,
'axes.labelsize':24,
'xtick.labelsize':28,
'ytick.labelsize':28,
'legend.fontsize': 24,
'axes.spines.right':False,
'axes.spines.top':False}
plt.rcParams.update(params)
plt.tick_params(axis="y", labelsize=28, labelrotation=20, labelcolor="black")
plt.tick_params(axis="x", labelsize=28, labelrotation=20, labelcolor="black")
plt.ylabel('RT Time (millisecond)', fontsize=24)
plt.title('# Participating RSUs', fontsize=24)
# plt.savefig('RSUs.pdf', bbox_inches='tight')
plt.show()
You can pass yerr as a pair [lower_errors, upper_errors] where you can control lower_errors :
lowers = np.minimum(rttStds,rttMeans)
p1 = plt.bar(ind, rttMeans, width, yerr=[lowers,rttStds], log=False, capsize = 16, color='green', hatch="/", error_kw=dict(elinewidth=3,ecolor='black'))
Output:

Hist wrong binwidth with logarithmix x and y axis

I need to plot a hist with bot logarithmic y and x-axis, but I'd like also to have hist's bins displayed of same size.
How can I achieve this result with the following code (the x used is very long so I have intentionally avoided to insert it):
import matplotlib as plt
import numpy as np
fig, ax1 = plt.subplots()
hist, bins, _ = ax1.hist(x, log=True, color="red", rwidth=0.5)
plt.xscale("log")
np_x = np.array(x)
print("np_x.mean() = " + str(np_x.mean()))
plt.axvline(np_x.mean() * 1.1, color='lime', linestyle='dashed', linewidth=3,
label='Mean: {:.2f}'.format(np_x.mean()))
handles, labels = ax1.get_legend_handles_labels()
binwidth = math.floor(bins[1] - bins[0])
mylabel = "Binwidth: {}".format(binwidth) + ", Bins: {}".format(len(hist))
red_patch = mpatches.Patch(color='red', label=mylabel)
handles = [red_patch] + handles
labels = [mylabel] + labels
ax1.legend(handles, labels)
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.show()

Basemap is returning blank after add meridians, paralles and scale

I am trying to plot a depth map using Basemap in python. The contour and pcolormesh are working, but them when I add meridians, parallels and scale is returning a blank image.
I have tried to plot one by one, excluding meridians and paralles, and adding just scale, but returns a blank map and it is the same with the others. I used the same code before and it was working...
import netCDF4 as nc
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib import ticker
grid = nc.Dataset('remo_grd.nc', mode='r')
h = grid.variables['h'][:]
h = h.astype(int)
h=-h
lon= grid.variables['lon_rho'][:]
lat= grid.variables['lat_rho'][:]
latmin = np.min(lat)
latmax= np.max(lat)
lonmax= np.max(lon)
lonmin= np.min(lon)
fig = plt.figure(1, figsize = (7,5.4), dpi = 100)
ax = fig.add_subplot(111)
m = Basemap(projection='merc', llcrnrlon=lonmin-0.2, urcrnrlon=lonmax+0.2, llcrnrlat=latmin-0.2, urcrnrlat=latmax+0.2, lat_ts=0, resolution='i')
xi, yi = m(lon,lat)
m.ax = ax
cs= m.pcolormesh(xi, yi, np.squeeze(h), shading = 'flat', zorder = 2)
levels = [-1000, -200]
a = m.contour(xi, yi, np.squeeze(h), levels, colors = 'black', linestyles = 'solid', linewidth= 1.5, extend = 'both', zorder = 3 )
plt.clabel(a, inline=2, fontsize= 10, linewidth= 1.0, fmt = '%.f', zorder= 4)
ax.text(0.5, -0.07, 'Longitude', transform=ax.transAxes, ha='center', va='center', fontsize = '10')
ax.text(-0.15, 0.5, 'Latitude', transform=ax.transAxes, ha= 'center', va='center', rotation='vertical', fontsize = '10')
m.drawcoastlines(linewidth=1.5, color = '0.1',zorder=5)
m.fillcontinents(color=('gray'),zorder=5 )
m.drawstates(linewidth = 0.5, zorder = 7)
m.drawmapboundary(color = 'black', zorder = 8, linewidth =1.2)
m.drawparallels(np.arange(int(latmin),int(latmax),3),labels=[1,0,0,0], linewidth=0.0, zorder =0)
m.drawmeridians(np.arange(int(lonmin),int(lonmax),3),labels=[0,0,0,1], linewidth=0.0)
cbar = plt.colorbar(cs, shrink=0.97, extend = 'both')
cbar.set_ticks([-10, -250, -500, -750, -1000, -1250, -1500, -1750, -2000, -2250, -2500])
cbar.set_ticklabels([-10, -250, -500, -750, -1000, -1250, -1500, -1750, -2000, -2250, -2500])
cbar.set_label('Meters (m)' , size = 10, labelpad = 20, rotation = 270)
ax = cbar.ax.tick_params(labelsize = 9)
titulo='Depth'
plt.title(titulo, va='bottom', fontsize='12')
#plot scale
dref=200
# Coordinates
lat0=m.llcrnrlat+0.9
lon0=m.llcrnrlon+1.9
#Tricked distance to provide to the the function
distance=dref/np.cos(lat0*np.pi/180.)
# Due to the bug, the function will draw a bar of length dref
scale=m.drawmapscale(lon0,lat0,lon0,lat0,distance, barstyle='fancy', units='km', labelstyle='simple',fillcolor1='w', fillcolor2='#555555', fontcolor='#555555', zorder = 8)
#Modify the labels with dref instead of distance
scale[12].set_text(dref/2)
scale[13].set_text(dref)
plt.show()
I've solved the problem! I was setting a specific order to plot each one of the details using the function zorder, so I was overlapping the data

Categories

Resources