diff --git a/raytracing/rays.py b/raytracing/rays.py
index 7787434..11de6ad 100644
--- a/raytracing/rays.py
+++ b/raytracing/rays.py
@@ -29,6 +29,12 @@ class Rays:
         self._thetaHistogram = None
         self._directionBinEdges = None
 
+        self._countHistogramParameters = None
+        self._xValuesCountHistogram = None
+
+        self._anglesHistogramParameters = None
+        self._xValuesAnglesHistogram = None
+
     def __len__(self) -> int:
         if self.rays is None:
             return 0
@@ -53,15 +59,17 @@ class Rays:
         return self._thetaValues
 
     def rayCountHistogram(self, binCount=None, minValue=None, maxValue=None):
-        if self._yHistogram is None:
-            if binCount is None:
-                binCount = 40
 
-            if minValue is None:
-                minValue = min(self.yValues)
+        if binCount is None:
+            binCount = 40
+
+        if minValue is None:
+            minValue = min(self.yValues)
+
+        if maxValue is None:
+            maxValue = max(self.yValues)
 
-            if maxValue is None:
-                maxValue = max(self.yValues)
+        if self._countHistogramParameters != (binCount, minValue, maxValue):
 
             (self._yHistogram, binEdges) = histogram(self.yValues,
                                                      bins=binCount,
@@ -70,27 +78,30 @@ class Rays:
             xValues = []
             for i in range(len(binEdges) - 1):
                 xValues.append((binEdges[i] + binEdges[i + 1]) / 2)
+            self._xValuesCountHistogram = xValues
 
-        return (xValues, self._yHistogram)
+        return (self._xValuesCountHistogram, self._yHistogram)
 
     def rayAnglesHistogram(self, binCount=None, minValue=None, maxValue=None):
-        if self._thetaHistogram is None:
-            if binCount is None:
-                binCount = 40
+        if binCount is None:
+            binCount = 40
 
-            if minValue is None:
-                minValue = min(self.thetaValues)
+        if minValue is None:
+            minValue = min(self.thetaValues)
 
-            if maxValue is None:
-                maxValue = max(self.thetaValues)
+        if maxValue is None:
+            maxValue = max(self.thetaValues)
+
+        if self._anglesHistogramParameters != (binCount, minValue, maxValue):
 
             (self._thetaHistogram, binEdges) = histogram(self.thetaValues, bins=binCount, range=(minValue, maxValue))
             self._thetaHistogram = list(self._thetaHistogram)
             xValues = []
             for i in range(len(binEdges) - 1):
                 xValues.append((binEdges[i] + binEdges[i + 1]) / 2)
+            self._xValuesAnglesHistogram = xValues
 
-        return (xValues, self._thetaHistogram)
+        return (self._xValuesAnglesHistogram, self._thetaHistogram)
 
     def display(self, title="Intensity profile", showTheta=True):
         plt.ioff()
@@ -159,6 +170,12 @@ class Rays:
         self._thetaHistogram = None
         self._directionBinEdges = None
 
+        self._countHistogramParameters = None
+        self._xValuesCountHistogram = None
+
+        self._anglesHistogramParameters = None
+        self._xValuesAnglesHistogram = None
+
     def load(self, filePath, append=False):
         with open(filePath, 'rb') as infile:
             loadedRays = pickle.Unpickler(infile).load()

rayCountHistogram() and rayAnglesHistogram() of Rays raise exception when already computed
When we compute `rayCountHistogram()` for a first time, it works perfectly. But when we run it a second time, it throws an exception because a variable is referenced before asignment.
diff --git a/raytracing/tests/testsRays.py b/raytracing/tests/testsRays.py
new file mode 100644
index 0000000..9bb4c7c
--- /dev/null
+++ b/raytracing/tests/testsRays.py
@@ -0,0 +1,34 @@
+import unittest
+import envtest  # modifies path
+from raytracing import *
+
+inf = float("+inf")
+
+
+class TestRays(unittest.TestCase):
+
+    def testRayCountHist(self):
+        r = Rays([Ray()])
+        init = r.rayCountHistogram()
+        self.assertIsNotNone(init)  # First time compute
+        final = r.rayCountHistogram()
+        self.assertIsNotNone(final)  # Second time compute, now works
+
+        self.assertTupleEqual(init, final)
+        final = r.rayCountHistogram(10)
+        self.assertNotEqual(init, final)
+
+    def testRayAnglesHist(self):
+        r = Rays([Ray()])
+        init = r.rayAnglesHistogram()
+        self.assertIsNotNone(init)  # First time compute
+        final = r.rayAnglesHistogram()
+        self.assertIsNotNone(final)  # Second time compute, now works
+
+        self.assertTupleEqual(init, final)
+        final = r.rayAnglesHistogram(10)
+        self.assertNotEqual(init, final)
+
+
+if __name__ == '__main__':
+    unittest.main()

pip install -e .
parse_log_pytest
matplotlib numpy
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
Brotli @ file:///croot/brotli-split_1736182456865/work
contourpy @ file:///croot/contourpy_1738160616259/work
coverage==7.8.0
cycler @ file:///tmp/build/80754af9/cycler_1637851556182/work
exceptiongroup==1.2.2
execnet==2.1.1
fonttools @ file:///croot/fonttools_1737039080035/work
importlib_resources @ file:///croot/importlib_resources-suite_1720641103994/work
iniconfig==2.1.0
kiwisolver @ file:///croot/kiwisolver_1672387140495/work
matplotlib==3.9.2
numpy @ file:///croot/numpy_and_numpy_base_1736283260865/work/dist/numpy-2.0.2-cp39-cp39-linux_x86_64.whl#sha256=3387e3e62932fa288bc18e8f445ce19e998b418a65ed2064dd40a054f976a6c7
packaging @ file:///croot/packaging_1734472117206/work
pillow @ file:///croot/pillow_1738010226202/work
pluggy==1.5.0
pyparsing @ file:///croot/pyparsing_1731445506121/work
PyQt6==6.7.1
PyQt6_sip @ file:///croot/pyqt-split_1740498191142/work/pyqt_sip
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.0.0
pytest-mock==3.14.0
pytest-xdist==3.6.1
python-dateutil @ file:///croot/python-dateutil_1716495738603/work
-e git+https://github.com/DCC-Lab/RayTracing.git@25d5ffdd500afc561b8ce7d25dded3b532fd44a1#egg=raytracing
sip @ file:///croot/sip_1738856193618/work
six @ file:///tmp/build/80754af9/six_1644875935023/work
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
tornado @ file:///croot/tornado_1733960490606/work
typing_extensions==4.13.0
unicodedata2 @ file:///croot/unicodedata2_1736541023050/work
zipp @ file:///croot/zipp_1732630741423/work

name: RayTracing
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - blas=1.0=openblas
  - brotli-python=1.0.9=py39h6a678d5_9
  - bzip2=1.0.8=h5eee18b_6
  - c-ares=1.19.1=h5eee18b_0
  - ca-certificates=2025.2.25=h06a4308_0
  - contourpy=1.2.1=py39hdb19cb5_1
  - cycler=0.11.0=pyhd3eb1b0_0
  - cyrus-sasl=2.1.28=h52b45da_1
  - expat=2.6.4=h6a678d5_0
  - fontconfig=2.14.1=h55d465d_3
  - fonttools=4.55.3=py39h5eee18b_0
  - freetype=2.12.1=h4a9f257_0
  - icu=73.1=h6a678d5_0
  - importlib_resources=6.4.0=py39h06a4308_0
  - jpeg=9e=h5eee18b_3
  - kiwisolver=1.4.4=py39h6a678d5_0
  - krb5=1.20.1=h143b758_1
  - lcms2=2.16=hb9589c4_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - lerc=4.0.0=h6a678d5_0
  - libabseil=20250127.0=cxx17_h6a678d5_0
  - libcups=2.4.2=h2d74bed_1
  - libcurl=8.12.1=hc9e6f67_0
  - libdeflate=1.22=h5eee18b_0
  - libedit=3.1.20230828=h5eee18b_0
  - libev=4.33=h7f8727e_1
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgfortran-ng=11.2.0=h00389a5_1
  - libgfortran5=11.2.0=h1234567_1
  - libglib=2.78.4=hdc74915_0
  - libgomp=11.2.0=h1234567_1
  - libiconv=1.16=h5eee18b_3
  - libnghttp2=1.57.0=h2d74bed_0
  - libopenblas=0.3.21=h043d6bf_0
  - libpng=1.6.39=h5eee18b_0
  - libpq=17.4=hdbd6064_0
  - libprotobuf=5.29.3=hc99497a_0
  - libssh2=1.11.1=h251f7ec_0
  - libstdcxx-ng=11.2.0=h1234567_1
  - libtiff=4.5.1=hffd6297_1
  - libuuid=1.41.5=h5eee18b_0
  - libwebp-base=1.3.2=h5eee18b_1
  - libxcb=1.15=h7f8727e_0
  - libxkbcommon=1.0.1=h097e994_2
  - libxml2=2.13.5=hfdd30dd_0
  - lz4-c=1.9.4=h6a678d5_1
  - matplotlib=3.9.2=py39h06a4308_1
  - matplotlib-base=3.9.2=py39hbfdbfaf_1
  - mysql=8.4.0=h721767e_2
  - ncurses=6.4=h6a678d5_0
  - numpy=2.0.2=py39heeff2f4_0
  - numpy-base=2.0.2=py39h8a23956_0
  - openjpeg=2.5.2=he7f1fd0_0
  - openldap=2.6.4=h42fbc30_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pcre2=10.42=hebb0a14_1
  - pillow=11.1.0=py39hcea889d_0
  - pip=25.0=py39h06a4308_0
  - pyparsing=3.2.0=py39h06a4308_0
  - pyqt=6.7.1=py39h6a678d5_0
  - pyqt6-sip=13.9.1=py39h5eee18b_0
  - python=3.9.21=he870216_1
  - python-dateutil=2.9.0post0=py39h06a4308_2
  - qtbase=6.7.3=hdaa5aa8_0
  - qtdeclarative=6.7.3=h6a678d5_0
  - qtsvg=6.7.3=he621ea3_0
  - qttools=6.7.3=h80c7b02_0
  - qtwebchannel=6.7.3=h6a678d5_0
  - qtwebsockets=6.7.3=h6a678d5_0
  - readline=8.2=h5eee18b_0
  - setuptools=72.1.0=py39h06a4308_0
  - sip=6.10.0=py39h6a678d5_0
  - six=1.16.0=pyhd3eb1b0_1
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tornado=6.4.2=py39h5eee18b_0
  - tzdata=2025a=h04d1e81_0
  - unicodedata2=15.1.0=py39h5eee18b_1
  - wheel=0.45.1=py39h06a4308_0
  - xcb-util-cursor=0.1.4=h5eee18b_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.21.0=py39h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - zstd=1.5.6=hc292b87_0
  - pip:
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - iniconfig==2.1.0
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pytest-xdist==3.6.1
      - typing-extensions==4.13.0
prefix: /opt/conda/envs/RayTracing

raytracing/tests/testsRays.py::TestRays::testRayAnglesHist raytracing/tests/testsRays.py::TestRays::testRayCountHist
raytracing/rays.py
raytracing/rays.py