This is my code.
time = sig[:, 0] # data first column: time
displacement = sig[:, 1] # data second column: displacement
font = {'family': 'Times New Roman', 'weight': 'bold', 'size': 16}
fig, ax = plt.subplots(figsize = (9, 8)) # set figure size (width,height)
ax.plot(time, displacement, linewidth = 2)
ax.set_xlim(0, 3e-3) # set x-axis limit
ax.set_ylim(-4e-6, 1e-6) # set y-axis limit
ax.set_xticklabels([0, 0.5, 1, 1.5, 2, 2.5, 3])
ax.tick_params(labelsize = 16) # tick_params can only change label size
labels = ax.get_xticklabels() + ax.get_yticklabels()
for label in labels: # thus use for loop(?) change font name and weight
label.set_fontname('Times New Roman')
label.set_fontweight('bold')
ax.set_xlabel('Time (msec.)', font)
ax.set_ylabel('Displacement (m)', font)
plt.show()
And this is the code's result.
But actually, that's what I want to get.
How can I change the notation form from 1e-6 to 10^-6 and also make the font bold.
To change the scientific notation of ticklabel:
ax.ticklabel_format(useMathText=True)
To change the text properties, grab the text object with:
ty = ax.yaxis.get_offset_text()
ty.set_fontweight('bold')
ty.set_size(16)
Related
I have a vertical bar plot in matplotlib and would like the color of the bars to vary based on the values in an array. I know that in plot.scatter() this can be done with cmap=''. But i can't seem to find the same functionality with plot.bar(). Any advice? is the figure in question.
fig, season = plt.subplots()
# show the phenology season
season.set_ylabel('GPP 20th percent yearly max')
season.tick_params('y', colors = 'blue', labelsize =24)
season.bar(x = pheno['SRO_SoS'], height= pheno['SRO_20th'], width =
pheno['SRO_DateDelta'], zorder=1, color = 'wheat', align =
'edge')
season.set_ylim(0,5)
temp = season.twinx()
temp.plot(df_w.index, df_w['TA_F'],color = 'red', label = 'Tempurature',
linewidth = 2)
# set x-label
temp.set_xlabel('Date')
temp.tick_params('x', labelsize =24)
# set primary y label
temp.set_ylabel('Tempurature (C)')
temp.tick_params('y', colors = 'red', labelsize =24)
# set x-axis limits as the min and max of the series
temp.set_xlim(date2num([df_w.index.min(), df_w.index.max()]))
temp.xaxis.set_major_formatter(mdates.DateFormatter('%d-%m-%Y'))
temp.xaxis.set_major_locator(mdates.YearLocator(1, month=1, day=1))
temp.set_ylim(2,30)
temp.grid(True)
plt.show()
You can give an array to the color argument in your season.bar(). That should work.
If you want to give discrete colors, here is an example.
fig, season = plt.subplots()
clist = ['red', 'blue', 'green']
season.bar(x = range(1, 11), height= range(10, 30, 2), width = 0.8, zorder=1, color = clist, align = 'edge')
Discrete colors - Output plot
For using cmap continuous colors, here is another example.
fig, season = plt.subplots()
my_cmap = plt.get_cmap("viridis")
colorrange = [0,0.25,0.5,0.75,1.0] #Range should be in range of 0 to 1
season.bar(x = range(1, 11), height= range(10, 30, 2), width = 0.8, zorder=1, color=my_cmap(colorrange), align = 'edge')
Continuous colors - Output plot
I have plotted my figure and formatted the decimal points of the second Y-axis ticks to 0. But the y-axis tick values are rounded up to the same value. I don't want to manually set the tick frequency because the data change in each plot. What can I do to make sure the y-axis only shows '0, 1, 2, 3, 4'. The original y data are all in 'int' format.
Besides, x and y ticks are also not shown in the figure, despite that I put ax.tick_params() in the code. Any help will be much appreciated!
if not yrfullinfo.empty:
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(yrfullinfo['Yr'], yrfullinfo['mean'], label = 'mean', zorder = 10)
ax1.plot(yrfullinfo['Yr'], yrfullinfo['CI-2.5%'], label = 'CI-2.5%', c = 'darkorange', zorder = 10)
ax1.plot(yrfullinfo['Yr'], yrfullinfo['CI-97.5%'], label = 'CI-97.5%', c = 'darkorange', zorder = 10)
ax2.plot(yrfullinfo['Yr'], yrfullinfo['count'], label = 'count', ls = '--', c = 'k', zorder = 0)
ax1.set_xlabel("Year")
ax1.set_ylabel("mg/m2/yr")
ax2.set_ylabel('core count')
ax1.legend(loc = 2)
ax2.legend(loc = 9)
ax1.set_xlim([1690,2010])
ax1.set_ylim(ymin=0)
ax2.set_ylim(ymin=0)
ax1.tick_params(axis="x", direction="out")
ax1.tick_params(axis="y", direction="inout")
ax2.tick_params(axis="y", direction="inout")
ax1.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))
ax2.yaxis.set_major_formatter(FormatStrFormatter('%.0f'))
ax1.grid(False)
ax2.grid(False)
For each of the y-axes (ax1 and ax2), you should set the y-ticks. The ax.plot function will automatically set x and y limits. You can use the same limits, and just change the stepsize of the tick marks, then you could use ax.get_xlim() to discover what limits Matplotlib has already set.
start, end = ax2.get_ylim()
ax2.yaxis.set_ticks(np.arange(start, end, 1.0)) #as you want to set ax2 ticks to 1
Add this code right after ax2.set_ylim(ymin=0) and that should work
My output for some random numbers....as I had set mean for random number between 0 and 1 while the median line was set to random number between 0 and 4, matplotlib chose those limits and the stepsize of 1.0 along with your other code ensured that the ticks were 1 unit apart.
How to choose the font size for text annotations inside the bars of the bar graph with the condition:
Text will completely cover the rectangular bar area.
Please go through the diagram and code for better clarity about the problem.
So, the requirement is only : font size should be relative to bars in the bar graphs
Code
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# Plot styles
mpl.style.use("ggplot")
# data
fruits = pd.Series(index = ["Apples", "Oranges", "Watermelon"], data = [324,518, 258])
# Bar graph for Fruits
# figure
plt.figure(figsize = (7,5))
# bar graph
fruits.plot(kind = "bar", color = ["red", "orange", "green"], alpha = 0.6, width = 0.5, )
# percentage of each fruit type
categories = list(fruits.index)
categories_percent = [100*(value/fruits.sum()) for value in fruits ]
# categories annotations coordinates
ax = plt.gca() # get current axes
rects = ax.patches # rectangles axes of bars in the graph
# annotations
for i in range(len(categories)):
plt.annotate(f"{categories[i]} - {categories_percent[i] : 0.2f}%",
xy = (rects[i].get_x() + rects[i].get_width()/2,
rects[i].get_y() + (ax.get_yticks()[1] - ax.get_yticks()[0])*.2),
fontsize = [20,28,12][i], # Chosen by hit and trial for adjustment
color = "white",
ha = "center",
rotation = 90,
)
plt.ylabel("# Counts", fontsize = 15,)
plt.title("Distribution of Fruits", fontsize = 25, fontname = "Monospace", alpha = .6)
plt.xticks([])
plt.tight_layout(rect=[0, 0, 1, 1])
plt.show()
How to deal with this line of code fontsize = [20,28,12][i], # Chosen by hit and trial for adjustment to adjust the font size dynamically with respect to bar area?
Updating the existing annotation with an adjustable fontsize
From a logical perspective figure sizes' y acts as a scaling factor for height.
Think .get_height as a relative height of the figure.
The actual height is the y scaling factor multiplied with .get_height.
About including breadth, we can include relative breadth which is just .get_width (not get_width*x), however it would just act as a constant, since it's relative width.
We can't include actual width because the font would adjusted unproportionally for y axis.
x,y=15,15
plt.figure(figsize = (x,y))
for i in range(len(categories)):
txt="{} - {: 0.2f} %".format(categories[i],categories_percent[i])
plt.annotate(txt,
xy = (rects[i].get_x() + rects[i].get_width()/2,
rects[i].get_y() + (ax.get_yticks()[1] - ax.get_yticks()[0])*.2),
fontsize = (rects[i].get_height())*y*.2/len(txt), # Chosen by hit and trial for adjustment
color = "white",
ha = "center",
rotation = 90,
)
The entire code can be written more cleanly as follows
# data
fruits = pd.Series(index = ["Apples", "Oranges", "Watermelon"], data=[324,518, 258])
# calculate percent
per = fruits.div(fruits.sum()).mul(100).round(2)
# bar graph
y = 5
ax = fruits.plot(kind="bar", color=["red", "orange", "green"], alpha=0.6, width=0.5, figsize=(7, y), rot=0)
labels = [f'{fruit} - {per[fruit]}%' for fruit in fruits.index]
# annotations:
for label, p in zip(labels, ax.patches):
left, bottom, width, height = p.get_bbox().bounds
fs = height * y * 0.18 / len(label)
ax.annotate(label, xy=(left+width/2, bottom+height/2), ha='center', va='center', rotation=90, fontsize=fs)
plt.ylabel("# Counts", fontsize=15,)
plt.title("Distribution of Fruits", fontsize=25, fontname="Monospace", alpha=.6)
plt.xticks([])
plt.tight_layout(rect=[0, 0, 1, 1])
plt.show()
For figsize=(15,15):
For figsize=(8,8):
For figsize=(7,5):
There are much more information overlap in my figure, I want to make it more clear, how to modify my code?
df = pd.read_excel('biodye_24samples.xlsx', header=None)
x_coord =df.values[0, 1:]
df_name = df.values[1:, 0]
df_val = df.values[1:,1:]
fig = plt.figure()
for i in range(1, 13):
ax = fig.add_subplot(3, 4, i)
ax.plot(x_coord, df_val[2*i - 2,],'r', label='SCI')
ax.plot(x_coord, df_val[2*i - 1,],'b', label='SCE')
plt.xlabel('Wavelength(nm)', fontsize = 10)
plt.ylabel('Reflectance', fontsize = 10)
plt.legend()
plt.title(df_name[2*i - 2], fontsize = 10)
plt.show()
Two recommendations:
fig.tight_layout() to fix the padding between and around the subplots.
Increase the figsize of the figure: fig = plt.figure(figsize=(...,...)), where the arguments are width and height in inches.
Consider using constrained layout rather than tight_layout. https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html For simple things they are the same, but for more complex layouts constrained_layout usually works better.
I am trying to plot some values on a polar plot. The code is as follows:
def plot_values(data):
bridge = CvBridge()
fig = figure(figsize=(4,4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
w,h = fig.canvas.get_width_height()
plot([0,0],[0,1], color=(0.5,0.5,0.5), linewidth = 3)
plot([1*pi/2,1*pi/2],[0,1], color=(0.5,0.5,0.5), linewidth = 3)
plot([2*pi/2,2*pi/2],[0,1], color=(0.5,0.5,0.5), linewidth = 3)
plot([3*pi/2,3*pi/2],[0,1], color=(0.5,0.5,0.5), linewidth = 3)
HAS= len(HAS_names)*4
radii=np.repeat(data,HAS)
width = 2*np.pi/HAS
for i in range(0, len(HAS_names)):
radii[i] = AUC_value[HAS_names[i]]/HAS_frames[i] #assignment done through lists
theta = np.arange(0.0, 2*np.pi, 2*np.pi/HAS)
bars = ax.bar(theta, radii, width=width, bottom=0.0)
xT=PLT.xticks()[0]
xL=['','HAS','','HAD','','TAS','','TAD']
PLT.xticks(xT, xL)
for r,bar in zip(radii, bars):
bar.set_facecolor( cm.jet(r/10.))
bar.set_alpha(0.5)
fig.canvas.draw()
canvas = PLT.get_current_fig_manager().canvas
canvas.draw()
I get the output as follows:
I am trying to plot the values occurring in the quadrant labeled HAS and rest on the region need to blank. I tried removing radii=np.repeat(data,HAS) and declare it as global variable within the function itself, but I needed to assign some value to radii initially before the for loop.
Any help is appreciated.