vcat
  • VCAT Documention

Example Notebooks

  • Tutorial Overview
  • Plotting Images
  • Modifying Images
  • Plotting ImageCubes
  • Modifying ImageCubes
  • Alignment
  • Model Component Analysis
  • Ridgeline Fitting
  • Stacking
  • Turnover Frequency

Code Documentation

  • Code Overview
  • ImageData
  • ImageCube
  • vcat.helpers

About

  • License
  • Release Notes
vcat
  • Example Notebooks
  • Ridgeline Fitting
  • Edit on GitHub

In [1]:
Copied!
from vcat import ImageData
from vcat import ImageData
2025-09-07 21:31:41,033 - INFO - vcat - Logging initialized. Log file: Console only.
2025-09-07 21:31:41,033 - INFO - vcat - No environment variable VCAT_CONFIG found, will use defaults.
2025-09-07 21:31:41,034 - INFO - vcat - Using DIFMAP path: /usr/local/difmap/uvf_difmap_2.5g/
Thank you for using VCAT. Have fun with VLBI!

If you are using this package please cite VCAT Team et al. 2025 ....
In [2]:
Copied!
#Let's load some data
data=ImageData("../dataset_example/3C111_X_2014_05_08/3C111_X_2014_05_08.fits", #Stokes I Fits
               "../dataset_example/3C111_X_2014_05_08/3C111_X_2014_05_08.uvf") #uvf file (not necessary, but better)

#get some info and plot it
print(data)
data.plot()
#Let's load some data data=ImageData("../dataset_example/3C111_X_2014_05_08/3C111_X_2014_05_08.fits", #Stokes I Fits "../dataset_example/3C111_X_2014_05_08/3C111_X_2014_05_08.uvf") #uvf file (not necessary, but better) #get some info and plot it print(data) data.plot()
Image of the source 3C111 at frequency 8.4 GHz on 2014-05-08 
    Total cleaned flux: 3815.199 mJy 
    Image Noise: 0.246 mJy using method 'Histogram Fit'
No polarization data loaded.
No model loaded. Clean model info: 
    Model Flux: 3815.199 mJy 
    Number of Components: 1555
No description has been provided for this image
Out[2]:
<vcat.plots.fits_image.FitsImage at 0x7f94ba22b370>
In [3]:
Copied!
#There are currently two methods implemented to derive a ridgeline
#Let's start with the "slices" method which will rotate the jet to the y-axis and then performs an analysis on each horizontal pixelslice
#Note that this method might not work for strongly bent jets

#To get the ridgeline we can do
ridgeline, _ = data.get_ridgeline(method="slices")

#this operation will automatically attach the new ridgeline to the ImageData object (data.ridgeline), so we can immediately plot it
data.plot(plot_ridgeline=True,ridgeline_color="green")
#There are currently two methods implemented to derive a ridgeline #Let's start with the "slices" method which will rotate the jet to the y-axis and then performs an analysis on each horizontal pixelslice #Note that this method might not work for strongly bent jets #To get the ridgeline we can do ridgeline, _ = data.get_ridgeline(method="slices") #this operation will automatically attach the new ridgeline to the ImageData object (data.ridgeline), so we can immediately plot it data.plot(plot_ridgeline=True,ridgeline_color="green")
2025-09-07 21:31:58,775 - INFO - vcat - Automatically determined jet direction 63.0°.
No description has been provided for this image
Out[3]:
<vcat.plots.fits_image.FitsImage at 0x7f95019a8190>
In [4]:
Copied!
#The ridgeline itself has some useful plot methods that can be used as follows:

#For better visibility, we will arrange them in a 2x2 subplot grid using matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2,2,figsize=(12,10))

#Flux profile
ridgeline.plot("intensity",fig=fig,ax=ax[0,0],show=False)

#opening angle
ridgeline.plot("open_angle",fig=fig,ax=ax[0,1],show=False)

#jet width/collimation profile, including fits
ridgeline.plot("width",fig=fig,ax=ax[1,0],fit=True,show=False)

#ridgeline itself
ridgeline.plot("ridgeline",fig=fig,ax=ax[1,1],show=False)

#and finally display all the plots
plt.tight_layout()
plt.show()


#Note that all of these values are also accesible manually, if you prefer doing your own custom plots
open_angle=data.ridgeline.open_angle #.width, .dist, .intensity, .X_ridg, .Y.ridg
#The ridgeline itself has some useful plot methods that can be used as follows: #For better visibility, we will arrange them in a 2x2 subplot grid using matplotlib import matplotlib.pyplot as plt fig, ax = plt.subplots(2,2,figsize=(12,10)) #Flux profile ridgeline.plot("intensity",fig=fig,ax=ax[0,0],show=False) #opening angle ridgeline.plot("open_angle",fig=fig,ax=ax[0,1],show=False) #jet width/collimation profile, including fits ridgeline.plot("width",fig=fig,ax=ax[1,0],fit=True,show=False) #ridgeline itself ridgeline.plot("ridgeline",fig=fig,ax=ax[1,1],show=False) #and finally display all the plots plt.tight_layout() plt.show() #Note that all of these values are also accesible manually, if you prefer doing your own custom plots open_angle=data.ridgeline.open_angle #.width, .dist, .intensity, .X_ridg, .Y.ridg
No description has been provided for this image
In [5]:
Copied!
#If the automatic detection does not work, we can choose to manually provide the jet angle
jet_angle=63
auto_rotate=False
#additionally, we also want to find the counterjet, this is possible by setting
counterjet=True

#Additionally we can apply some cuts for the fits
cut_radial=3.0 #signal-to-noise cut for pixels to consider in the fit
cut_final=5.0 #signal-to-noise cut for the final peak flux

#And adjust the final chi-squared value which is used to determine good fits for the width and opening angle
chi_sq_val=100.0

#Let's do the fit again including counterjet
ridgeline, counter_ridgeline = data.get_ridgeline("slices",counterjet=counterjet,jet_angle=jet_angle,auto_rotate=auto_rotate,
                                                  cut_radial=cut_radial,cut_final=cut_final,chi_sq_val=chi_sq_val)

#and plot the data including the counterjet
data.plot(plot_ridgeline=True,ridgeline_color="green",plot_counter_ridgeline=True,counter_ridgeline_color="purple")
#If the automatic detection does not work, we can choose to manually provide the jet angle jet_angle=63 auto_rotate=False #additionally, we also want to find the counterjet, this is possible by setting counterjet=True #Additionally we can apply some cuts for the fits cut_radial=3.0 #signal-to-noise cut for pixels to consider in the fit cut_final=5.0 #signal-to-noise cut for the final peak flux #And adjust the final chi-squared value which is used to determine good fits for the width and opening angle chi_sq_val=100.0 #Let's do the fit again including counterjet ridgeline, counter_ridgeline = data.get_ridgeline("slices",counterjet=counterjet,jet_angle=jet_angle,auto_rotate=auto_rotate, cut_radial=cut_radial,cut_final=cut_final,chi_sq_val=chi_sq_val) #and plot the data including the counterjet data.plot(plot_ridgeline=True,ridgeline_color="green",plot_counter_ridgeline=True,counter_ridgeline_color="purple")
No description has been provided for this image
Out[5]:
<vcat.plots.fits_image.FitsImage at 0x7f9500a5b640>
In [6]:
Copied!
#if there is a counterjet ridgeline and a jet ridgeline defined, we can plot the jet to counterjet profile
data.jet_to_counterjet_profile()
#if there is a counterjet ridgeline and a jet ridgeline defined, we can plot the jet to counterjet profile data.jet_to_counterjet_profile()
No description has been provided for this image
In [7]:
Copied!
#Let's also have a look at the second method that is implemented, called "polar",
#This method converts the image to polar coordinates and performs a gaussian fit for every azimuthal slice
#This method currently only works without counterjet

data=data.center()

#sometimes this method can be problematic in the inner region close to the jet, so you can define a start_radius in mas where to begin the fit
start_radius=1.5 #mas

#Let's give it a try:
ridgeline, _ = data.get_ridgeline("polar",start_radius=start_radius)

#let's plot it
data.plot(plot_ridgeline=True,ridgeline_color="green")
#Let's also have a look at the second method that is implemented, called "polar", #This method converts the image to polar coordinates and performs a gaussian fit for every azimuthal slice #This method currently only works without counterjet data=data.center() #sometimes this method can be problematic in the inner region close to the jet, so you can define a start_radius in mas where to begin the fit start_radius=1.5 #mas #Let's give it a try: ridgeline, _ = data.get_ridgeline("polar",start_radius=start_radius) #let's plot it data.plot(plot_ridgeline=True,ridgeline_color="green")
2025-09-07 21:33:30,012 - INFO - vcat - will apply shift (x,y): [-0.04000000009455 : 0.0] mas
2025-09-07 21:33:49,154 - INFO - vcat - Automatically determined jet direction 63.0°.
No description has been provided for this image
Out[7]:
<vcat.plots.fits_image.FitsImage at 0x7f9500651130>
In [8]:
Copied!
#Let's create the same ridgeline plots as before for comparison with the 'slices' method:

#For better visibility, we will arrange them in a 2x2 subplot grid using matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2,2,figsize=(12,10))

#Flux profile
ridgeline.plot("intensity",fig=fig,ax=ax[0,0],show=False)

#opening angle
ridgeline.plot("open_angle",fig=fig,ax=ax[0,1],show=False)

#jet width/collimation profile, including fits
ridgeline.plot("width",fig=fig,ax=ax[1,0],fit=True,show=False)

#ridgeline itself
ridgeline.plot("ridgeline",fig=fig,ax=ax[1,1],show=False)

#and finally display all the plots
plt.tight_layout()
plt.show()
#Let's create the same ridgeline plots as before for comparison with the 'slices' method: #For better visibility, we will arrange them in a 2x2 subplot grid using matplotlib import matplotlib.pyplot as plt fig, ax = plt.subplots(2,2,figsize=(12,10)) #Flux profile ridgeline.plot("intensity",fig=fig,ax=ax[0,0],show=False) #opening angle ridgeline.plot("open_angle",fig=fig,ax=ax[0,1],show=False) #jet width/collimation profile, including fits ridgeline.plot("width",fig=fig,ax=ax[1,0],fit=True,show=False) #ridgeline itself ridgeline.plot("ridgeline",fig=fig,ax=ax[1,1],show=False) #and finally display all the plots plt.tight_layout() plt.show()
No description has been provided for this image
In [ ]:
Copied!

Previous Next

Built with MkDocs using a theme provided by Read the Docs.
GitHub « Previous Next »