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
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
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)
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)])
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.
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)