How to smooth graph curves - python

I am drawing graphs based on an excel data and I have average value, minimum value, and maximum value. The problem is that when I draw a graph the curves are not smooth and it is very hard to understand. I am using matplotlib to draw a graph
GoogleDrive: data.csv
Columns in Excel data Like
Code
# libraries
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.style.use('seaborn-darkgrid')
# Data
df_Data = pd.read_csv('/home/khawar/Downloads/wandb_export_2021-10-09T14_05_20.127+09_00.csv')
print(df_Data.head())
# df = pd.DataFrame(
# {'x_values': df_Data['Step'], 'y1_values': df_Data['VIT - loss__MIN'], 'y2_values': df_Data['VIT+OverLP (Ours) - loss__MIN']})
df = pd.DataFrame(
{'x_values': df_Data['Step'], 'y1_values': df_Data['VIT - acc'], 'y2_values': df_Data['VIT+OverLP (Ours) - acc']})
font = {'family': 'serif',
'color': 'black',
'weight': 'normal',
'size': 11,
}
# multiple line plots
# plt.plot('x_values', 'y3_values', data=df, color='green', linewidth=1.5, label="ResNet-18")
plt.plot('x_values', 'y2_values', data=df, color='blue', linewidth=1.5, label="hello")
plt.plot('x_values', 'y1_values', data=df, color='red', linewidth=1.5, label="hi")
# plt.rcParams["font.weight"] = "bold"
# plt.rcParams["axes.labelweight"] = "bold"
# plt.xticks(weight='bold')
# plt.yticks(weight='bold')
# Display y axis values
# ax = plt.gca()
# ax.set_ylim([0.0, 10.0])
plt.xlabel('Number of iteration', fontdict=font)
plt.ylabel('Training loss', fontdict=font)
# plt.ylabel('Average accuracy (%)', fontdict=font)
plt.savefig('/media/khawar/HDD_Khawar/Thesis/deeplearning_acc.png')
plt.legend()
# show graph
plt.show()
Result
If you will see the graph curves are not smooth and I just want to smooth it

You can plot a smooth curve by first determining the spline curve’s coefficients using the scipy.interpolate.make_interp_spline()
# Dataset
x1 = np.array([1, 2, 3, 4, 5, 6, 7, 8])
y1 = np.array([20, 30, 5, 12, 39, 48, 50, 3])
x2 = np.array([10, 20, 30, 40, 50, 60, 70, 80])
y2 = np.array([2, 3, 5, 1, 3, 4, 5, 3])
X_Y_Spline1 = make_interp_spline(x1, y1)
X_Y_Spline2 = make_interp_spline(x2, y2)
# Returns evenly spaced numbers
# over a specified interval.
X_1 = np.linspace(x1.min(), x1.max(), 500)
Y_1 = X_Y_Spline1(X_1)
X_2 = np.linspace(x2.min(), x2.max(), 500)
Y_2 = X_Y_Spline2(X_2)
# Plotting the Graph
plt.plot(X_1, Y_1)
plt.plot(X_2, Y_2)
plt.title("Plot Smooth Curve Using the scipy.interpolate.make_interp_spline() Class")
plt.xlabel("X")
plt.ylabel("Y")
plt.show()

Related

how can I plot missing points to a full circle?

I have 9 temperature points. 1 in the center and 8 on the circle. I need to create a heatmap in a circle. I set the points at which to perform calculations, and use the scipy.interpolate.griddata, but the full circle is not drawn, program draws an octagon. How can i fill in the missing parts?
import scipy.interpolate
import numpy
import matplotlib
import matplotlib.pyplot as plt
import math
# close old plots
plt.close("all")
# some parameters
xy_center = [2,2] # center of the plot
radius = 2 # radius
# mostly original code
meanR = [33.9, 34.2, 33.1, 33.5, 33., 32.7, 32.3, 31.8, 35.]
x = numpy.array([2, 2, 2+math.sqrt(2), 4, 2+math.sqrt(2), 2, 2+(-math.sqrt(2)), 0, 2+(-math.sqrt(2))])
y = numpy.array([2, 4, 2+math.sqrt(2), 2, 2+(-math.sqrt(2)), 0, 2+(-math.sqrt(2)), 2, 2+math.sqrt(2)])
z = meanR
xi, yi = numpy.mgrid[x.min():x.max():500j, y.min():y.max():500j]
zi = scipy.interpolate.griddata((x, y), z, (xi, yi), method='cubic')
# make figure
fig = plt.figure(figsize=(10, 10))
# set aspect = 1 to make it a circle
ax = fig.add_subplot(111, aspect = 1)
# use different number of levels for the fill and the lines
CS = ax.contourf(xi, yi, zi, 300, cmap=plt.cm.viridis, zorder=1)
# make a color bar
cbar = fig.colorbar(CS, ax=ax)
# add the data points
ax.scatter(x, y, marker = 'o', c = 'b', s = 15, zorder = 3)
for i in range(9):
ax.annotate(str(z[i]), (x[i],y[i]))
# draw a circle
circle = matplotlib.patches.Circle(xy = xy_center, radius = radius, edgecolor = "k", facecolor = "none")
ax.add_patch(circle)
# remove the ticks
ax.set_xticks([])
ax.set_yticks([])
# set axes limits
ax.set_xlim(-0.5, 4.5)
ax.set_ylim(-0.5, 4.5)
plt.show()
Radial basis functions (Rbf) can be used to interpolate/extrapolate your data.
scipy.interpolation Here is a modified code that produces the plot you need.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import math
from scipy.interpolate import Rbf
# some parameters
xy_center = [2,2] # center of the plot
radius = 2 # radius
# Data part
# ---------
# mostly original code
meanR = [33.9, 34.2, 33.1, 33.5, 33., 32.7, 32.3, 31.8, 35.] #9 points data
x = np.array([2, 2, 2+math.sqrt(2), 4, 2+math.sqrt(2), 2, 2+(-math.sqrt(2)), 0, 2+(-math.sqrt(2))])
y = np.array([2, 4, 2+math.sqrt(2), 2, 2+(-math.sqrt(2)), 0, 2+(-math.sqrt(2)), 2, 2+math.sqrt(2)])
z = meanR
# use RBF (Radial basis functions) that allows extrapolation
rbf = Rbf(x, y, z, epsilon=radius+1) #epsilon is based on some parameters of the data
# Interpolation/extrapolation
# ---------------------------
xi, yi = np.mgrid[x.min():x.max():500j, y.min():y.max():500j]
# applies and get inter/extra-polated values
zi = rbf(xi, yi)
# make zi outside circle --> np.none
midr,midc = zi.shape[0]/2, zi.shape[1]/2
for er in range(zi.shape[0]):
for ec in range(zi.shape[1]):
if np.abs(math.sqrt((er-midr)**2 + (ec-midc)**2))>zi.shape[0]/2:
# outside the circle, dont plot this pixel
zi[er][ec] = np.nan
pass
pass
# make figure
fig = plt.figure(figsize=(8, 8))
# set aspect = 1 to make it a circle
ax = fig.add_subplot(111, aspect = 1)
# add the data points
ax.scatter(x, y, marker = 'o', c = 'b', s = 15, zorder = 3)
for i in range(9):
ax.annotate(str(z[i]), (x[i],y[i]))
# draw a circle
circle = matplotlib.patches.Circle(xy = xy_center, radius = radius, edgecolor = "k", facecolor = "none")
ax.add_patch(circle)
CS = ax.contourf(xi, yi, zi, 300, cmap=plt.cm.viridis, zorder=1)
cbar = fig.colorbar(CS, ax=ax, shrink=0.7) # make a color bar
# remove the ticks
ax.set_xticks([])
ax.set_yticks([])
# set axes limits
ax.set_xlim(-0.5, 4.5)
ax.set_ylim(-0.5, 4.5)
plt.show()
The result:

How to get arithmetically growing minor ticks with matplotlib?

The following snippet creates a list myHLines of (y) values that is arithmetically growing.
I want to use them as minor y ticks in a matplotlib plot.
How can I do this?
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'a': [1, 3, 10, 30, 100]})
myMin = df.a.min()
myMax = df.a.max()
ratio = 3
myHLines = [myMin * ratio ** i for i in range(1000) if myMin * ratio ** i < myMax]
print("myHLines=", myHLines)
# myHLines= [1, 3, 9, 27, 81]
plt.plot(df, '-o', markersize=2, c='r')
plt.show()
Is the scale of the y-axis you want to achieve the y-axis shown in the graph below?
plt.plot(df, '-o', markersize=2, c='r')
locs, labels = plt.yticks()
new_y = sorted(myHLines + locs.tolist()[1:-1])
# print(new_y)
plt.yticks(new_y)
plt.show()

Grouped Bar Plot with Pattern Fill using Python and Matplotlib

I found the following barplot on the following website: http://ndaratha.blogspot.com/2015/03/grouped-bar-plot
According to the website, it corresponds to the following code
import matplotlib.pyplot as plt
# Input data; groupwise
green_data = [16, 23, 22, 21, 13, 11, 18, 15]
blue_data = [ 3, 3, 0, 0, 5, 5, 3, 3]
red_data = [ 6, 6, 6, 0, 0, 0, 0, 0]
black_data = [25, 32, 28, 21, 18, 16, 21, 18]
labels = ['XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII']
# Setting the positions and width for the bars
pos = list(range(len(green_data)))
width = 0.15 # the width of a bar
# Plotting the bars
fig, ax = plt.subplots(figsize=(10,6))
bar1=plt.bar(pos, green_data, width,
alpha=0.5,
color='w',
hatch='x', # this one defines the fill pattern
label=labels[0])
plt.bar([p + width for p in pos], blue_data, width,
alpha=0.5,
color='w',
hatch='o',
label=labels[1])
plt.bar([p + width*2 for p in pos], red_data, width,
alpha=0.5,
color='k',
hatch='',
label=labels[2])
plt.bar([p + width*3 for p in pos], black_data, width,
alpha=0.5,
color='w',hatch='*',
label=labels[3])
# Setting axis labels and ticks
ax.set_ylabel('Number of Switching')
ax.set_xlabel('Strategy')
ax.set_title('Grouped bar plot')
ax.set_xticks([p + 1.5 * width for p in pos])
ax.set_xticklabels(labels)
# Setting the x-axis and y-axis limits
plt.xlim(min(pos)-width, max(pos)+width*5)
plt.ylim([0, max(green_data + blue_data + red_data) * 1.5])
# Adding the legend and showing the plot
plt.legend(['OLTC', 'SVC', 'SC', 'OLTC+SC+SVC'], loc='upper right')
plt.grid()
plt.show()
But when I try running the code, I get the following output
Does anyone know what I'm doing wrong or what I should do to get the desired output?
You need to add edgecolor = "k" in your plt.bar() code which gives black colors to the bar edges, and you can get the barplot you want.
When you add edgecolor = "k", code is as follows,
import matplotlib.pyplot as plt
# Input data; groupwise
green_data = [16, 23, 22, 21, 13, 11, 18, 15]
blue_data = [ 3, 3, 0, 0, 5, 5, 3, 3]
red_data = [ 6, 6, 6, 0, 0, 0, 0, 0]
black_data = [25, 32, 28, 21, 18, 16, 21, 18]
labels = ['XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII']
# Setting the positions and width for the bars
pos = list(range(len(green_data)))
width = 0.15 # the width of a bar
# Plotting the bars
fig, ax = plt.subplots(figsize=(10,6))
bar1=plt.bar(pos, green_data, width,
alpha=0.5,
color='w',
hatch='x', # this one defines the fill pattern
label=labels[0],edgecolor='black')
plt.bar([p + width for p in pos], blue_data, width,
alpha=0.5,
color='w',
hatch='o',
label=labels[1],edgecolor='black')
plt.bar([p + width*2 for p in pos], red_data, width,
alpha=0.5,
color='k',
hatch='',
label=labels[2],edgecolor='black')
plt.bar([p + width*3 for p in pos], black_data, width,
alpha=0.5,
color='w',hatch='*',
label=labels[3],edgecolor='black')
# Setting axis labels and ticks
ax.set_ylabel('Number of Switching')
ax.set_xlabel('Strategy')
ax.set_title('Grouped bar plot')
ax.set_xticks([p + 1.5 * width for p in pos])
ax.set_xticklabels(labels)
# Setting the x-axis and y-axis limits
plt.xlim(min(pos)-width, max(pos)+width*5)
plt.ylim([0, max(green_data + blue_data + red_data) * 1.5])
# Adding the legend and showing the plot
plt.legend(['OLTC', 'SVC', 'SC', 'OLTC+SC+SVC'], loc='upper right')
plt.grid()
plt.show()

How to create many 3D cylindrical plots on an axis system?

Are there libraries or methods in python that are capable of creating plots that look like this? (preferably based around MatPlotLib for the sake of embedding the plots in HTML pages)
My goal is to create 3D renderings of data that is read from a Neo4J database and model them as the cylinders above.
The code below attempts to create a similar 3D plot (not cylindrical but rectangular) with legends from a dataframe. The plot is interactive. Resources: 1, 2, 3, 4 (Jupyter Notebook 5.0.0, Python 3.6.6)
Import libraries
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.patches as mpatches # for legends
%matplotlib notebook
Create a sample dataframe
# Create two sets of identical xpos and ypos
# So taht the z-values are plotted at same location for stacking
xtemp = np.random.randint(1, 10, size=5)
ytemp = np.random.randint(1, 10, size=5)
df = pd.DataFrame({
# category
'season': ['S1']*5 + ['S2']*5 + ['S3']*5,
#'wins': np.random.randint(1, 10, size=15),
# define pos
'xpos' : list(xtemp)+list(xtemp)+list(xtemp),
'ypos' : list(ytemp)+list(ytemp)+list(ytemp),
'zpos' : np.zeros(15),
# define delta
'dx': 0.8*np.ones(15),
'dy': 0.8*np.ones(15),
'dz': np.random.randint(1, 5, size=15), #np.ones(15)
})
df.head(5)
Plot the figure
Note: Figure are in two parts: (1) 2D plot for the N-S, E-W lines and (2) 3D bar plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# ..................
# Line-1 on x-y plane
x = [4, 4]
y = [-3, 12]
ax.plot(x, y, zs=0, zdir='z', color='orange', alpha=0.8)
# Line-2 on x-y plane
y = [4, 4]
x = [-3, 12]
ax.plot(x, y, zs=0, zdir='z', color='blue', alpha=0.5)
# Creat multiple overlap plots within a loop
color = ['#6495ED', '#6E8B3D', '#FFB90F']
slist = ['S1', 'S2', 'S3']
stack_zpos = pd.Series(np.zeros(5))
for i in range(0,3):
q = df[df['season']==slist[i]].reset_index(inplace=False)
ax.bar3d(q.xpos, q.ypos, stack_zpos, q.dx, q.dy, q.dz, color=color[i], alpha=1)
stack_zpos += q.dz # values added here for stacking
Annotate lines and remove z-axis panes and grid lines
# Remove the z-axis panes, grids and lines
alpha = 0
ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, alpha))
ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, alpha))
#
ax.zaxis._axinfo["grid"]['color'] = (1.0, 1.0, 1.0, alpha)
ax.w_yaxis._axinfo["grid"]['linewidth'] = 0
ax.w_xaxis._axinfo["grid"]['linewidth'] = 0
#
ax.w_zaxis.line.set_lw(0.)
ax.set_zticks([])
#
ax.set_zlabel("") # remove z-axis label 'z'
# ..........
# Annotate the N, S, E, W lines on the x-y plane
zdirs = (None, 'x', 'y', 'z', (1, 1, 0), (1, 1, 1))
xs = (4, 4, -3, 12)
ys = (-3,12, 4, 4)
zs = (0, 0, 0, 0)
i=0 # Counter
nsew = ['N', 'S', 'E', 'W'] # list of labels
for zdir, x, y, z in zip(zdirs, xs, ys, zs):
label = '{0}'.format(nsew[i])
#label = 'N, S, E, W' #% (x, y, z, zdir)
ax.text(x, y, z, label, zdir)
i +=1
Create and add legends to the plot
# Add legend
patch1 = mpatches.Patch(color=color[0], label=slist[0])
patch2 = mpatches.Patch(color=color[1], label=slist[1])
patch3 = mpatches.Patch(color=color[2], label=slist[2])
plt.legend(handles=[patch1, patch2,patch3])
Visualize plot
plt.show()

matplotlib colorbar boundaries do not implemented

I am trying to create several plots all with the same colorbar limits in a loop.
I set the limits of the contour plot with map.contourf(x, y, U_10m, vmin=0, vmax=25) and this seems to give consistent colour scales for each plot. However, when I use cbar = plt.colorbar(boundaries=np.linspace(0,1,25), ticks=[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]) # sets all cbar to same limits each plot does not have the same colorbar limits (examples of two plots with different colorbars and code below).
from netCDF4 import Dataset as NetCDFFile
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
def wrf_tseries_contour_plotter (
ncfile, time_ind, lowerllat, upperrlat, lowerllon, upperrlon, output_dir):
'''
EDITED FROM http://www.atmos.washington.edu/~ovens/wrfwinds.html
'''
print 'timestep:', + time_ind
#which figure is being generated 0 = 00:00, 144 = 23:50
nc = NetCDFFile(ncfile, 'r')
#
# get the actual longitudes, latitudes, and corners
lons = nc.variables['XLONG'][time_ind]
lats = nc.variables['XLAT'][time_ind]
#get the u10 to plot as a contour instead of t2m
U10_raw = nc.variables['U10'][time_ind] #61 is the index for 10:00am
V10_raw = nc.variables['V10'][time_ind]
#bodge to calculate U from U and V (u10 = sqrt(u^2+v^2))
v2 = np.square(V10_raw)
u2 = np.square(U10_raw)
U_10m = np.sqrt(u2 + v2)
# Make map
map = Basemap(projection='cyl',llcrnrlat=lowerllat,urcrnrlat=upperrlat,
llcrnrlon=lowerllon,urcrnrlon=upperrlon,
resolution='h')
# lllat, urlat,lllon, urlon set outside of f(x) lower left and
# upper right lat/lon for basemap axis limits
x, y = map(lons[:,:], lats[:,:])
map.contourf(x, y, U_10m, vmin=0, vmax=25)
map.drawcoastlines(linewidth = 0.5, color = '0.15')
#thinner lines for larger scale map
#plt.clim(0, 25) #added
cbar = plt.colorbar(boundaries=np.linspace(0,1,25), ticks=[0, 2, 4, 6,
8, 10, 12, 14, 16, 18, 20, 22, 24]) # sets all cbar to same limits
cbar.set_label('10m U (m/s)', size=12)
cbar.ax.set_yticklabels([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24])
#cbar.set_clim(0, 25)
time_str = str(time_ind)
plt.title('gust 20070724' + '_' + time_str)
fig_name = '\gust20070724_'+ time_str + '.png'
plt.savefig(output_dir + fig_name)
plt.close()
#set inputs for wrf_tseries_contour_plotter(ncfile, time_ind, lllat, urlat,
lllon, urlon, output_dir)
ncfile = 'E:\WRFout_UK2Fino\wrfout_d03_2007-07-24_00%3A00%3A00'
tlist = np.arange(0,145)
#set the lower left/upper right lat/lon for axis limits on the maps
lowerllat=48
upperrlat=63
lowerllon=-10
upperrlon=25
#set output directory for figures
output_dir = '''C:\cbar_test'''
for time_ind in tlist:
wrf_tseries_contour_plotter(ncfile, time_ind, lowerllat, upperrlat,
lowerllon, upperrlon, output_dir)
You have to use vmin and vmax values to set boundaries of a colorbar like in this example:
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
# test data
x = np.linspace(0,15,100)
X,Y = np.meshgrid(x,x)
SPD1 = np.sqrt(X*X + Y*Y)
SPD2 = SPD1 * 1.3
fig = plt.figure()
# implement boundaries of colorbar and it ticks
vmin, vmax = 0, 26
levels = np.linspace(vmin,vmax,14)
# 1st subplot
ax1 = fig.add_subplot(221)
# Set contour levels and limits
CF1 = ax1.contourf(X, Y, SPD1, levels=levels, vmax=vmax, vmin=vmin)
cbar = plt.colorbar(CF1)
cbar.set_label('10m U (m/s)', size=12)
#2nd subplot
ax1 = fig.add_subplot(222)
CF1 = ax1.contourf(X, Y, SPD2, levels=levels, vmax=vmax, vmin=vmin)
cbar = plt.colorbar(CF1)
cbar.set_label('10m U (m/s)', size=12)
plt.tight_layout()
plt.show()
However you have to select vmin, vmax correctly because of if your values are outside boundaries of colorbar they will not shown (right upper corner of 2nd subplot).

Categories