How to plot a contour within a bounded area? - python-3.x

I would like help to plot a counterf only within the region bounded by the blue area in the image, not in the whole graph. I am trying to use matplotlib mpath and mpatches but I am getting several errors.
How could I plot the difference in levels (contorf) only within the area delimited by the blue markings?
Here is my code and the picture
#import base modules
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import LinearNDInterpolator
from matplotlib.collections import PatchCollection
import matplotlib.path as mpath
import matplotlib.patches as mpatches
from mpl_toolkits.axes_grid1 import make_axes_locatable
#Loading the images
img1953 = plt.imread('O1953_9960_A3_1m.tif')
img1999 = plt.imread('O1999_9523_A3_1m.tif')
img2004 = plt.imread('O2004_2385c_A3_1m.tif')
#extract data from surfer files with pandas and name the columns as x and y, first line omited
area = pd.read_csv('diff_analyse_grd.bln', names=['x1', 'y1'], skiprows=1)
slope = pd.read_csv("Abbruchkante.bln", names=['x2', 'y2'], skiprows=1)
crack = pd.read_csv("Anrisskante.bln", names=['x3', 'y3'], skiprows=1)
xmin, xmax = -1100, -200 #set the maximum and miniumum values for the axIs:
ymin, ymax = 1500, 2100
#Read csv from grid/countour file, 1999
grid = np.loadtxt('kr_99_A3_o25.dat', delimiter = ' ', skiprows = 1, usecols = [1,2,3])
x99 = grid[:,0]
y99 = grid[:,1]
z99 = grid[:,2]
#linear space with 600x900 values between min and max graphic values
xi = np.linspace(xmin, xmax, 900)
yi = np.linspace(ymin, ymax, 600)
X, Y = np.meshgrid(xi, yi)
#Using LinearNDInterpolation, year 1999
interpolation99 = LinearNDInterpolator(list(zip(x99, y99)), z99)#https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.LinearNDInterpolator.html
zi99 = interpolation99(X, Y)
#Read csv from grid/countour file, year 1953
grid = np.loadtxt('kr_53_A3_o25.dat', delimiter = ' ', skiprows = 1, usecols = [1,2,3])
x53 = grid[:,0]
y53 = grid[:,1]
z53 = grid[:,2]
#Using LinearNDInterpolation, year 1953
interpolation53 = LinearNDInterpolator(list(zip(x53,y53)), z53)
zi53 = interpolation53(X,Y)
#Calculation of the hight variation:
dh5399 = zi53 - zi99
#Plot graph 1953 - 1999
plt.title('Hangrutschung im Blaubachgraben \n \n Differenz der Geländeoberflachen \n 1953 - 1999')
plt.imshow(img1953,cmap='gray', extent=(xmin, xmax, ymin, ymax))
plt.plot(area.x1,area.y1,'b-', label ='Studienbereich', linewidth = 2)
plt.plot(slope.x2,slope.y2,'r-', label = 'Abbruchkante')
plt.plot(crack.x3,crack.y3,'r--', label = 'Anrisskante')
cs = plt.contour(X,Y,zi99,levels=10, colors='#333')
plt.clabel(cs,inline=True, colors = 'k')
plt.legend(loc='upper right')
plt.xlabel('North [m]')
plt.ylabel('East [m]')
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax)
cs = plt.contourf(X, Y, dh5399, cmap='rainbow', vmin=-5, vmax=17)
#Setting colorbar right the axis
ax = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes('right',size='3%',pad=0.1)
cbar = plt.colorbar(cs, cax=cax)
cbar.set_label('\u0394H [m]', rotation = 360, loc = 'top')
plt.tight_layout()
plt.savefig('Dif1.png',dpi=400)
plt.show()

Related

How to adjust color in KDE scatter plot?

I wrote a program to plot oscilloscope data and make a KDE scatter plot with a colorbar. Unfortunately it requires a third party lib (readTrc) as well as the oscilloscope binary file which size is 200MB. The lib can be found on github.
import pandas as pd
import readTrc
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import collections
from scipy.stats import gaussian_kde
trcpath = 'filename.trc' #Binary Oscilloscope File (200 MB)
datX, datY, m = readTrc.readTrc(trcpath)
srx, sry = pd.Series(datX * 1000), pd.Series(datY * 1000)
df = pd.concat([srx, sry], axis = 1)
df.set_index(0, inplace = True)
df = df.abs() #Build Dataframe from above file
fig = plt.figure()
#Eliminate Noise
df[df < 3] = None
df = df.dropna()
#x and y axes data to plot
q1 = np.array(df[1].tolist()[:-2])
q2 = np.array(df[1].tolist()[1:-1])
q3 = np.array(df[1].tolist()[2:])
dq1 = q2 - q1
dq2 = q3 - q2
#Create first Dataset
qqstack = []
xy = np.vstack([dq1,dq2])
#Determine max value for colorbar (highest repeating x/y combination)
df_d = pd.DataFrame([dq1,dq2]).T
for idx, row in df_d.iterrows():
if row[0] == row[1]:
qqstack.append((row[0], row[1]))
cbar_max = collections.Counter(qqstack).most_common(1)[0][-1]
#sort to show most present values last
z = gaussian_kde(xy)(xy)
idx = z.argsort()
x, y, z = dq1[idx], dq2[idx], z[idx]
#plot graph
plt.scatter(x, y,
c=z,
s=20,
cmap = plt.cm.get_cmap('jet'))
#create colormap variable
sm = plt.cm.ScalarMappable(cmap = plt.cm.get_cmap('jet'),
norm = matplotlib.colors.PowerNorm(vmin = -0.1, vmax = cbar_max, gamma = 1))
sm._A = []
fig.colorbar(sm, ticks = range(0, cbar_max, 250))
plt.grid(zorder = 0, alpha = 0.3)
plt.xlabel('dq1 / mV')
plt.ylabel('dq2 / mV')
plt.show()
How can I adjust the color allocation in the plot? I want there to be less blue space so the transition is visible more, like on this graph:

Scatter plot colorbar based on datapoint cluster

I am trying to achieve a plot similar to this one:
The color shows the clustering of the datapoints.
My code so far:
import pandas as pd
import readTrc
import matplotlib.pyplot as plt
import numpy as np
import os
import gc
trcpath = 'filename.trc'
datX, datY, m = readTrc.readTrc(trcpath)
srx, sry = pd.Series(datX * 1000), pd.Series(datY * 1000)
df_plot = pd.concat([srx, sry], axis = 1)
df_plot.set_index(0, inplace = True)
fig, ax = plt.subplots()
#Eliminate Noise
df_plot[df_plot < 3] = 0
df = df_plot[df_plot > 3]
df[df < 3] = None
df = df.dropna()
#Plot Parameters
p = np.array(df[1].tolist()[:-1])
p_nach = np.array(df[1].tolist()[1:])
d_t = np.array(pd.Series(df.index).diff().tolist()[1:])
#Graph Limit
graphlim = 101
#Plot
plt.scatter(p, p_nach,
edgecolors = 'none',
c = p,
s = 20,
cmap=plt.cm.get_cmap('jet'))
plt.xlim(0,graphlim)
plt.ylim(0,graphlim)
plt.xticks(range(0,graphlim,int(graphlim/10)))
plt.yticks(range(0,graphlim,int(graphlim/10)))
plt.colorbar()
plt.grid(zorder = 0, alpha = 0.3)
ax.set_xlabel('p / mV')
ax.set_ylabel('p_nach / mV')
##plt.savefig(dpi = 300)
plt.show()
##plt.close()
##fig.clear()
##gc.collect()
print('Progress... done!')
As you can see, the colorbar does not represent the clustering and instead the place on the x-axis. How do I configure my colorbar to represent the amount of datapoints in an area?
Folder with files: Link
import pandas as pd
import readTrc
import matplotlib.pyplot as plt
import numpy as np
import os
import gc
trcpath = 'filename.trc'
datX, datY, m = readTrc.readTrc(trcpath)
df = pd.DataFrame({'time': datX * 1000, 'volts': datY * 1000})
reduce_noise_df = df[df.volts >= 3.0]
d_t = reduce_noise_df.time.diff()[1:]
p = reduce_noise_df.volts[:-1]
p_nach = reduce_noise_df.volts[1:]
#Graph Limit
graphlim = 41
#Plot
fig, ax = plt.subplots(figsize=(6,6))
plt.scatter(p, p_nach,
edgecolors = 'none',
c = d_t,
s = 20,
cmap=plt.cm.get_cmap('jet'))
plt.xlim(0, graphlim)
plt.ylim(0, graphlim)
plt.xticks(range(0, graphlim, int(graphlim/10)))
plt.yticks(range(0, graphlim, int(graphlim/10)))
plt.colorbar()
plt.grid(zorder = 0, alpha = 0.3)
ax.set_xlabel('p / mV')
ax.set_ylabel('p_nach / mV')
plt.show()
I began be removing unnecessary code
The main issue was c = p instead of c = d_t.
Plot of waveform from your Le Croy WR640Zi colored by data density
import pandas as pd
import readTrc
import matplotlib.pyplot as plt
import numpy as np
import os
import gc
from scipy.stats import gaussian_kde
trcpath = 'filename.trc'
datX, datY, m = readTrc.readTrc(trcpath)
df = pd.DataFrame({'time': datX * 1000, 'volts': datY * 1000})
reduce_noise_df = df[df.volts >= 3.0]
y = np.array(reduce_noise_df.volts.tolist())
x = np.array(reduce_noise_df.time.tolist())
# Calculate point density
xy = np.vstack([x, y])
z = gaussian_kde(xy)(xy)
# Sort points by density
idx = z.argsort()
x, y, z = x[idx], y[idx], z[idx]
#Plot
fig, ax = plt.subplots(figsize=(6,6))
plt.scatter(x, y,
edgecolors = 'none',
c = z,
s = 20,
cmap=plt.cm.get_cmap('jet'))
plt.colorbar()
plt.grid(zorder = 0, alpha = 0.3)
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Voltage (mV)')
plt.show()

Scaling a PDF to show 100% at peak

I'm displaying a histogram of my data, with an overlaid PDF. My plots all look something like this:
and I'm trying to scale the red curve to show 100% at the peak.
My following toy code is identical to what I'm actually using, apart from the lines in between the two %:
%
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as stats
import numpy as np
my_randoms = np.random.normal(0.5, 1, 50000)
dictOne = {"delta z":my_randoms}
df = pd.DataFrame(dictOne)
df = df[df['delta z'] > -999]
%
fig, ax = plt.subplots()
h, edges, _ = ax.hist(df['delta z'], alpha = 1, density = False, bins = 100)
param = stats.norm.fit(df['delta z'].dropna()) # Fit a normal distribution to the data
pdf_fitted = stats.norm.pdf(df['delta z'], *param)
x = np.linspace(*df['delta z'].agg([min, max]), 100) # x-values
binwidth = np.diff(edges).mean()
ax.plot(x, stats.norm.pdf(x, *param)*h.sum()*binwidth, color = 'r')
# Decorations
graph_title = 'U-B'
plt.grid(which = 'both')
plt.title(r'$\Delta z$ distribution for %s'%graph_title, fontsize = 25)
plt.xlabel(r'$\Delta z = z_{spec} - z_{photo}$', fontsize = 25)
plt.ylabel('Number', fontsize = 25)
plt.xticks(fontsize = 25)
plt.yticks(fontsize = 25)
xmin, xmax = min(df['delta z']), max(df['delta z'])
plt.xlim(xmin, xmax)
plt.annotate(
r'''$\mu_{\Delta z}$ = %.3f
$\sigma_{\Delta z}$ = %.3f'''%(param[0], param[1]),
fontsize = 25, color = 'r', xy=(0.85, 0.85), xycoords='axes fraction')
How would I define another axes object from 0 to 100 on the right-hand side and map the PDF to that?
Or is there a better way to do it?
This is kind of a follow-up to my previous question.
You can use density=True in plotting the histogram.
You use .twinx():
fig = plt.figure(figsize=(10, 8), dpi=72.0)
n_rows = 2
n_cols = 2
ax1 = fig.add_subplot(n_rows, n_cols, 1)
ax2 = fig.add_subplot(n_rows, n_cols, 2)
ax3 = ax1.twinx()
https://matplotlib.org/gallery/api/two_scales.html

x-Axis in scatter subplot plot does not follow changes of widgets controls [duplicate]

The next code plots three subplots.
from ipywidgets import widgets
from IPython.display import display
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
fig, (ax1, ax2,ax3) = plt.subplots(nrows=3, figsize=(10,9))
line1, = ax1.semilogx([],[], label='Multipath')
hline1 = ax1.axhline(y = 0, linewidth=1.2, color='black',ls='--')
text1 = ax1.text(0, 0, "T Threshold",
verticalalignment='top', horizontalalignment='left',
transform=ax1.get_yaxis_transform(),
color='brown', fontsize=10)
#ax1.set_xlabel('Separation Distance, r (m)')
ax1.set_ylabel('Received Power, $P_t$ (dBm)')
ax1.grid(True,which="both",ls=":")
ax1.legend()
line2, = ax2.semilogx([],[], label='Monostatic Link')
hline2 = ax2.axhline(y = 0, linewidth=1.2, color='black',ls='--')
text2 = ax2.text(0, 0, "R Threshold",
verticalalignment='top', horizontalalignment='left',
transform=ax2.get_yaxis_transform(),
color='brown', fontsize=10)
#ax2.set_xlabel('Separation Distance, r (m)')
ax2.set_ylabel('Received Power, $P_t$ (dBm)')
ax2.grid(True,which="both",ls=":")
ax2.legend()
#line3, = ax3.semilogx([],[])
line3 = ax3.scatter([],[], c='blue', alpha=0.75, edgecolors='none', s=6)
ax3.set_xlabel('Separation Distance, r (m)')
ax3.set_ylabel('Probability of error')
ax3.grid(True,which="both",ls=":")
ax3.set_xscale('log')
#ax3.set_xlim((0.55,13.5))
ax3.set_ylim((0,1))
def update_plot(h1, h2):
D = np.arange(0.5, 12.0, 0.0100)
r = np.sqrt((h1-h2)**2 + D**2)
freq = 865.7 #freq = 915 MHz
lmb = 300/freq
H = D**2/(D**2+2*h1*h2)
theta = 4*np.pi*h1*h2/(lmb*D)
q_e = H**2*(np.sin(theta))**2 + (1 - H*np.cos(theta))**2
q_e_rcn1 = 1
P_x_G = 4 # 4 Watt EIRP
sigma = 1.94
N_1 = np.random.normal(0,sigma,D.shape)
rnd = 10**(-N_1/10)
F = 10
y = 10*np.log10( 1000*(P_x_G*1.622*((lmb)**2) *0.5*1) / (((4*np.pi*r)**2) *1.2*1*F)*q_e*rnd*q_e_rcn1 )
line1.set_data(r,y)
hline1.set_ydata(-18)
text1.set_position((0.02, -18.8))
ax1.relim()
ax1.autoscale_view()
######################################
rd =np.sqrt((h1-h2)**2 + D**2)
rd = np.sort(rd)
P_r=0.8
G_r=5 # 7dBi
q_e_rcn2 = 1
N_2 = np.random.normal(0, sigma*2, D.shape)
rnd_2 = 10**(-N_2/10)
F_2 = 126
y = 10*np.log10( 1000*(P_r*(G_r*1.622)**2*(lmb)**4*0.5**2*0.25)/((4*np.pi*rd)**4*1.2**2*1**2*F_2)*
q_e**2*rnd*rnd_2*q_e_rcn1*q_e_rcn2 )
line2.set_data(rd,y)
hline2.set_ydata(-80)
text2.set_position((0.02, -80.8))
ax2.relim()
ax2.autoscale_view()
#######################################
P_r = y
SNR = P_r - ( 20 + 10*np.log10(1.6*10**6)-174 )
CIR = P_r -( -100)
SNR_linear = 10**(SNR/10)
CIR_linear = (10**(CIR/10))/1000
SNIR = 1/( 1/SNR_linear + 1/CIR_linear )
K_dB = 3
K = 10**(K_dB/10)
BER = (1+K)/(2+2*K + SNIR)*np.exp(-3*SNIR/(2+K+SNIR))
prob_error = 1-((1-BER )**6)
#line3.set_data(rd,prob_error)
line3.set_offsets(np.c_[rd,prob_error])
ax3.relim()
ax3.autoscale_view()
fig.canvas.draw_idle()
r_height = widgets.FloatSlider(min=0.5, max=4, value=0.9, description= 'R_Height:')
t_height = widgets.FloatSlider(min=0.15, max=1.5, value=0.5, description= 'T_Height:')
widgets.interactive(update_plot, h1=r_height, h2=t_height)
Subplots 1st and 2nd change their axis limits with variations of the input parameters R_Height and T_Height. However, subplot 3rd does not make the relim() and autoscale() of the plot.
Is there any way to change the limits of the x-axis in a similar way of subplots 1st and 2nd?.
Regards
Both .relim() and .autoscale_view() do not take effect when the axes bounds have previously been set via .set_ylim(). So .set_ylim() needs to be removed from the code.
In addition updating the limits of a scatter plot (which is a matplotlib.collections.PathCollection) is a bit more complicated than for other plots.
You would first need to update the datalimits of the axes before calling autoscale_view(), because .relim() does not work with collections.
ax.ignore_existing_data_limits = True
ax.update_datalim(scatter.get_datalim(ax.transData))
ax.autoscale_view()
Here is a minimal reproducible example:
from ipywidgets import widgets
from IPython.display import display
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
x = np.arange(10)
fig, ax = plt.subplots()
scatter = ax.scatter(x,x, label="y = a*x+b")
ax.legend()
def update_plot(a, b):
y = a*x+b
scatter.set_offsets(np.c_[x,y])
ax.ignore_existing_data_limits = True
ax.update_datalim(scatter.get_datalim(ax.transData))
ax.autoscale_view()
fig.canvas.draw_idle()
a = widgets.FloatSlider(min=0.5, max=4, value=1, description= 'a:')
b = widgets.FloatSlider(min=0, max=40, value=10, description= 'b:')
widgets.interactive(update_plot, a=a, b=b)
As written in the documentation for Axes.relim(), Collections (which is the type returned by scatter()) are not supported at the moment.
Therefore you have to ajust the limits manually, something like
(...)
line3.set_offsets(np.c_[rd,prob_error])
ax3.set_xlim((min(rd),max(rd)))
ax3.set_ylim((min(prob_error),max(prob_error)))
It seems to me that all your plot share the same x values, though? If that's the case, you might want to use fig, (ax1, ax2,ax3) = plt.subplots((...), sharex=True). You will still have to set the ylim for ax3 by hand, but at least your x-axes will be the same across all subplots.
EDIT: I realize now that it looks like your data in ax3are bound between [0-1], and that you probably don't need to change the ylim() and that sharing the x-axis with the other subplots should be enough.

Matplotlib Line Rotation or Animation

I have created a polar plot and would like to mimic a doppler. This includes a 360 degree sweep around the circle (polar plot). Once the sweep gets to 360 degrees, it needs to go back to zero and continue the sweep.
How do I animate or rotate this line to constantly sweep around this circle? I only want one line to constantly sweep around this plot.
I have looked at several different examples, however, none that create this rotation.
import numpy as np
import math
import matplotlib.pyplot as plt
import pylab
import time
r = 90 * (math.pi/180)
t = 50000
az = 90
el = 5
fig = pylab.figure(figsize = [5.0, 5.0])
ax = fig.gca(projection = 'polar')
fig.canvas.set_window_title('Doppler')
ax.plot(r, t, color ='b', marker = 'o', markersize = '3')
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
currTime = time.time()
prevTime = currTime - 1
deltaTime = currTime - prevTime
outer_border_width = 1
screen_width = 500
screen_height = 500
midpoint = [int(screen_width/2), int(screen_height/2)]
radius = (midpoint[0])
sweep_length = radius - outer_border_width
angle = 50
sweep_interval = 10
sweep_speed = sweep_interval
x = sweep_length * math.sin(angle) + int(screen_width/2)
y = sweep_length * math.cos(angle) + int(screen_height/2)
az = az + ((360.0 / sweep_interval ) * deltaTime)
line1 = (midpoint, [50000, 50000])
#line2 = (midpoint, [20000, 20000])
ax.plot(line1, color = 'b', linewidth = 1)
#Increase the angle by 0.05 radians
angle = angle - sweep_speed
#Reset the angle to 0
if angle > 2 * math.pi:
angle = angle - 2 * math.pi
#ax.plot(line2, color = 'r', linewidth = 1)
#ax.lines.pop(0)
plt.show()
Below is a picture of what it currently looks like for reference:
Many thanks!
I do not understand much of your code, but in order to produce an animation you can use matplotlib.animation.FuncAnimation. Here, you'd give an array of angles to an updating function, which sets the data of the line for each frame.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation
r = 90 * (np.pi/180)
t = 50000
fig = plt.figure()
ax = fig.gca(projection = 'polar')
fig.canvas.set_window_title('Doppler')
ax.plot(r, t, color ='b', marker = 'o', markersize = '3')
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_ylim(0,1.02*t)
line1, = ax.plot([0, 0],[0,t], color = 'b', linewidth = 1)
def update(angle):
line1.set_data([angle, angle],[0,t])
return line1,
frames = np.linspace(0,2*np.pi,120)
fig.canvas.draw()
ani = matplotlib.animation.FuncAnimation(fig, update, frames=frames, blit=True, interval=10)
plt.show()

Resources