Function is not displayed correctly in matplotlib - python

I want to visualize a function that is discontinuous at a certain value of x (=2).
However I do not get what I hoped. My code is the following:
x = np.arange(-1, 4, 0.1)
y = 2 * x**2 / (x - 2)
df = pd.DataFrame({"x" : x , "y" : y})
% matplotlib inline
import matplotlib
from matplotlib import pyplot as plt
# Set up the graph
plt.xlabel('x')
plt.ylabel('y')
plt.xticks(np.arange(-1,4, 0.5))
plt.yticks(np.arange(-8, 8, 0.5))
plt.axhline()
plt.axvline()
plt.grid()
# Plot the function
plt.plot(df["x"], df["y"], color='red')
axes = plt.gca()
xmin = -1
xmax = 4
ymin = -8
ymax = 8
axes.set_xlim([xmin,xmax])
axes.set_ylim([ymin,ymax])
plt.axvline(2)
plt.show()
What I get is the following:
Why the y values for x > 2 do not appear?

The problem is that you've set your ylim in such a way that it cuts off the values for x > 2.
Consider the output of your function for inputs greater than 2:
f = lambda x: 2 * x**2 / (x - 2)
print([f(i) for i in np.arange(2.1, 4, 0.2)])
#[88.199999999999918, 35.266666666666644, 24.999999999999989, 20.828571428571422,
# 18.688888888888883, 17.472727272727269, 16.753846153846151, 16.333333333333332,
# 16.105882352941176, 16.010526315789473]
If you changed the ylim constraints, you'll see the plot below:
# Set up the graph
plt.xlabel('x')
plt.ylabel('y')
#plt.xticks(np.arange(-1,4, 0.5))
#plt.yticks(np.arange(-8, 8, 0.5))
plt.axhline()
plt.axvline()
plt.grid()
# Plot the function
plt.plot(df["x"], df["y"], color='red')
axes = plt.gca()
xmin = -1
xmax = 4
ymin = -8
ymax = 100
axes.set_xlim([xmin,xmax])
axes.set_ylim([ymin,ymax])
plt.axvline(2)
plt.show()

Related

Plotting histogram of probability function and results of inverse transform sampling

Here I tried to plot the probability function P(s)=C/s and then plot a histogram showing real probability function and then show the results of sampling:
import numpy as np
s_min = 1
s_max = 1000
# calculate the normalization constant
C = 1 / (np.log(s_max) - np.log(s_min))
u = np.random.rand(int(1000000))
s = s_min * np.exp(u * (np.log(s_max) - np.log(s_min)))
a = np.log10(min(s))
b = np.log10(max(s))
mybins = np.logspace(a, b, num=17)
plt.hist(s, bins=mybins, density=True, histtype='step', log=True, label='Random Numbers')
x = np.logspace(a, b, num=100)
y = C / x
plt.plot(x, y, 'r', label='Expected Distribution')
plt.xlabel('s')
plt.ylabel('P(s)')
plt.xscale('log')
plt.yscale('log')
plt.legend()
plt.show()
but the code is generating an empty plot with labels.
Tried to add %matplotlib inline and nothing changed

Gradient 2D plot using contourf

I did a test code brigging something I saw on stack on different topic, and try to assemble it to make what I need : a filled curve with gradient.
After validate this test code I will make a subplot (4 plots for 4 weeks) with the same min/max for all plot (it's a power consumption).
My code :
from matplotlib import pyplot as plt
import numpy as np
# random x
x = range(100)
# smooth random y
y = 0
result = []
for _ in x:
result.append(y)
y += np.random.normal(loc=0, scale=1)#, size=len(x))
y = result
y = list(map(abs, y))
# creation of z for contour
z1 = min(y)
z3 = max(y)/(len(x)+1)
z2 = max(y)-z3
z = [[z] * len(x) for z in np.arange(z1,z2,z3)]
num_bars = len(x) # more bars = smoother gradient
# plt.contourf(x, y, z, num_bars, cmap='greys')
plt.contourf(x, y, z, num_bars, cmap='cool', levels=101)
background_color = 'w'
plt.fill_between(
x,
y,
y2=max(y),
color=background_color
)
But everytime I make the code run, the result display a different gradient scale, that is not smooth neither even straight right.
AND sometime the code is in error : TypeError: Length of y (100) must match number of rows in z (101)
I'm on it since too many time, turning around, and can't figure where I'm wrong...
I finally find something particularly cool, how to :
have both filled gradient curves in a different color (thanks to JohanC in this topic)
use x axis with datetime (thanks to Ffisegydd in this topic)
Here the code :
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.dates as mdates
np.random.seed(2022)
st_date = '2022-11-01 00:00:00'
st_date = pd.to_datetime(st_date)
en_date = st_date + pd.DateOffset(days=7)
x = pd.date_range(start=st_date,end=en_date,freq='30min')
x = mdates.date2num(x)
y = np.random.normal(0.01, 1, len(x)).cumsum()
fig, ax = plt.subplots(figsize=(18, 5))
ax.plot(x, y, color='grey')
########################
# positives fill
#######################
grad1 = ax.imshow(
np.linspace(0, 1, 256).reshape(-1, 1),
cmap='Blues',
vmin=-0.5,
aspect='auto',
extent=[x.min(), x.max(), 0, y.max()],
# extent=[x[0], x[1], 0, y.max()],
origin='lower'
)
poly_pos = ax.fill_between(x, y.min(), y, alpha=0.1)
grad1.set_clip_path(
poly_pos.get_paths()[0],
transform=ax.transData
)
poly_pos.remove()
########################
# negatives fill
#######################
grad2 = ax.imshow(
np.linspace(0, 1, 256).reshape(-1, 1),
cmap='Reds',
vmin=-0.5,
aspect='auto',
extent=[x.min(), x.max(), y.min(), 0],
origin='upper'
)
poly_neg = ax.fill_between(x, y, y.max(), alpha=0.1)
grad2.set_clip_path(
poly_neg.get_paths()[0],
transform=ax.transData
)
poly_neg.remove()
########################
# decorations and formatting plot
########################
ax.xaxis_date()
date_format = mdates.DateFormatter('%d-%b %H:%M')
ax.xaxis.set_major_formatter(date_format)
fig.autofmt_xdate()
ax.grid(True)

Matplotlib plotting custom colormap with the plot

I have been following a tutorial on plotting F1 data over a circuit, color coded with the fastf1 library.
I wanted to add some extra's to the script to utilize the official team colors.
It works but the end result shows the colormap with the circuit covering the n bins 100.
In the picture above I used the same colormap as in the tutorial 'winter' so there is most certainly something wrong in my code.
However, the original tutorial gets a cleaner end result with only the circuit showing like this:
the tutorial in question uses a default colormap from matplotlib 'winter'. To get the team colors working I had to create a custom colormap from the 2 colors that are fetched from api.
Let's get into the code, I have tried so much and searched everywhere without success...
The custom colormap is build with this sequence of code I got from the matplotlib docs.
# Create custom colormap
teamcolor1 = to_rgb('{}'.format(team1_color))
teamcolor2 = to_rgb('{}'.format(team2_color))
colors = [teamcolor1, teamcolor2]
n_bins = [3, 6, 10, 100]
cmap_name = 'colors'
fig, axs = plt.subplots(2, 2, figsize=(6, 9))
fig.subplots_adjust(left=0.02, bottom=0.06, right=0.95, top=0.94, wspace=0.05)
x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2 * np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 10
for n_bin, ax in zip(n_bins, axs.ravel()):
colormap = LinearSegmentedColormap.from_list(cmap_name, colors, N=n_bin)
im = ax.imshow(Z, interpolation='nearest', origin='lower', cmap=colormap)
ax.set_title("N bins: %s" % n_bin)
fig.colorbar(im, ax=ax)
cm.register_cmap(cmap_name, colormap)
I register the colormap to easily call it later in the script with get_cmap.
The eventual plotting of the circuit is done in this piece of code:
x = np.array(telemetry['X'].values)
y = np.array(telemetry['Y'].values)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
fastest_driver_array = telemetry['Fastest_driver_int'].to_numpy().astype(float)
cmap = cm.get_cmap('winter', 2)
lc_comp = LineCollection(segments, norm=plt.Normalize(1, cmap.N+1), cmap=cmap)
lc_comp.set_array(fastest_driver_array)
lc_comp.set_linewidth(5)
plt.rcParams['figure.figsize'] = [18, 10]
plt.gca().add_collection(lc_comp)
plt.axis('equal')
plt.tick_params(labelleft=False, left=False, labelbottom=False, bottom=False)
cbar = plt.colorbar(mappable=lc_comp, boundaries=np.arange(1, 4))
cbar.set_ticks(np.arange(1.5, 9.5))
cbar.set_ticklabels(['{}'.format(driver1), '{}'.format(driver2)])
plt.savefig(
'{}_'.format(year) + '{}_'.format(driver1) + '{}_'.format(driver2) + '{}_'.format(circuit) + '{}.png'.format(
session), dpi=300)
plt.show()
This is where I think things go wrong, but I'm unsure of what is going wrong. I guess it has to do with how I use the colormap. But everything I changed broke the whole script.
As I don't have a lot of experience with matplotlib, it's getting very complicated.
As I don't want this question to be overly long the whole code can be read here:
https://gist.github.com/platinaCoder/7b5be22405f2003bd577189692a2b36b
Instead of creating a whole custome cmap, I got rid of this piece of code:
# Create custom colormap
teamcolor1 = to_rgb('{}'.format(team1_color))
teamcolor2 = to_rgb('{}'.format(team2_color))
colors = [teamcolor1, teamcolor2]
n_bins = [3, 6, 10, 100]
cmap_name = 'colors'
fig, axs = plt.subplots(2, 2, figsize=(6, 9))
fig.subplots_adjust(left=0.02, bottom=0.06, right=0.95, top=0.94, wspace=0.05)
x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2 * np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 10
for n_bin, ax in zip(n_bins, axs.ravel()):
colormap = LinearSegmentedColormap.from_list(cmap_name, colors, N=n_bin)
im = ax.imshow(Z, interpolation='nearest', origin='lower', cmap=colormap)
ax.set_title("N bins: %s" % n_bin)
fig.colorbar(im, ax=ax)
cm.register_cmap(cmap_name, colormap)
and replaced cmap = cm.get_cmap('colors', 2) with cmap = cm.colors.ListedColormap(['{}'.format(team1_color), '{}'.format(team2_color)])

How to center ticks and labels in a heatmap

I am plotting a heatmap using matplotlib like the figure below:
The plot is constructed via the code below:
C_range = 10. ** np.arange(-2, 8)
gamma_range = 10. ** np.arange(-5, 4)
confMat=np.random.rand(10, 9)
heatmap = plt.pcolor(confMat)
for y in range(confMat.shape[0]):
for x in range(confMat.shape[1]):
plt.text(x + 0.5, y + 0.5, '%.2f' % confMat[y, x],
horizontalalignment='center',
verticalalignment='center',)
plt.grid()
plt.colorbar(heatmap)
plt.subplots_adjust(left=0.15, right=0.99, bottom=0.15, top=0.99)
plt.ylabel('Cost')
plt.xlabel('Gamma')
plt.xticks(np.arange(len(gamma_range)), gamma_range, rotation=45,)
plt.yticks(np.arange(len(C_range)), C_range, rotation=45)
plt.show()
I need to center the ticks and labels on both axes. Any ideas?
For your specific code the simplest solution is to shift your tick positions by half a unit separation:
import numpy as np
import matplotlib.pyplot as plt
C_range = 10. ** np.arange(-2, 8)
gamma_range = 10. ** np.arange(-5, 4)
confMat=np.random.rand(10, 9)
heatmap = plt.pcolor(confMat)
for y in range(confMat.shape[0]):
for x in range(confMat.shape[1]):
plt.text(x + 0.5, y + 0.5, '%.2f' % confMat[y, x],
horizontalalignment='center',
verticalalignment='center',)
#plt.grid() #this will look bad now
plt.colorbar(heatmap)
plt.subplots_adjust(left=0.15, right=0.99, bottom=0.15, top=0.99)
plt.ylabel('Cost')
plt.xlabel('Gamma')
plt.xticks(np.arange(len(gamma_range))+0.5, gamma_range, rotation=45,)
plt.yticks(np.arange(len(C_range))+0.5, C_range, rotation=45)
plt.show()
As you can see, in this case you need to turn off the grid, otherwise it will overlap with your squares and clutter up your plot.

matplotlib 3d axes ticks, labels, and LaTeX

I am running this sample script, with the following modifications:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
ax.legend()
ax.set_xlabel('$X$', fontsize=20, rotation=150)
ax.set_ylabel('$Y$')
ax.set_zlabel(r'$\gamma$', fontsize=30, rotation=60)
ax.yaxis._axinfo['label']['space_factor'] = 3.0
plt.show()
How do I adjust the axis ticks to that of my choosing? I.e., how would I get the z-axis to only label 2, 0, and -2, and in the font size that I want? I know how to do this in 2D but not 3D.
The script above produces the following:
Why is the x-axis label distorted, which I wanted to do with this script, but not the z-axis label (gamma)? This does not make sense. I need this axis labeled in the Greek letter. How do I fix this?
How do I adjust the axis ticks to that of my choosing? I.e., how would
I get the z-axis to only label 2, 0, and -2, and in the font size that
I want? I know how to do this in 2D but not 3D.
You have to change properties of zticks.
Why is the x-axis label distorted, which I wanted to do with this
script, but not the z-axis label (gamma)? This does not make sense. I
need this axis labeled in the Greek letter. How do I fix this?
You have to disable autorotation for z axis labels. Look at the code below:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
ax.legend()
ax.set_xlabel('$X$', fontsize=20)
ax.set_ylabel('$Y$')
ax.yaxis._axinfo['label']['space_factor'] = 3.0
# set z ticks and labels
ax.set_zticks([-2, 0, 2])
# change fontsize
for t in ax.zaxis.get_major_ticks(): t.label.set_fontsize(10)
# disable auto rotation
ax.zaxis.set_rotate_label(False)
ax.set_zlabel('$\gamma$', fontsize=30, rotation = 0)
plt.show()
The for loop is not necessary, to change the size of your ticks you can use:
ax.zaxis.set_tick_params(labelsize=10)

Categories

Resources