skip to Main Content

I am trying to "fold" an exponential plot (and a fit to it – see the first image below) around a discrete interval on the x-axis (a.k.a a "modulo plot"). The aim is that after 10 x-units the exponential is continued on the same plot from 0 for the 10 to 20 interval, as shown on a second "photoshopped" image below.

The MWE code is below:

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt

Generate points

x=np.arange(20)
y=np.exp(-x/10)

Fit to data

def fit_func(x, t):
    return np.exp(-x/t)
par, pcov = optimize.curve_fit(f=fit_func, xdata=x, ydata=y)

Plot data and fit function

fig, ax = plt.subplots()
ax.plot(x,y, c='g', label="Data");
ax.plot(x,fit_func(x, par), c='r', linestyle=":", label="Fit");
ax.set_xlabel("x (modulo 10)")
ax.legend()
plt.savefig("fig/mod.png", dpi=300)

What I have: Origianl exponential from 0 to 20

What I want: Modulo/folded exponential in intervals of 10

2

Answers


  1. You could try to simply write:

    ax.plot(x % 10,y, c='g', label="Data")
    ax.plot(x % 10, f, c='r', linestyle=":", label="Fit")
    

    but then you get confusing lines connecting the last point of one section to the first point of the next.

    Another idea is to create a loop to plot every part separately. To avoid multiple legend entries, only the first section sets a legend label.

    import numpy as np
    from scipy import optimize
    import matplotlib.pyplot as plt
    
    x=np.arange(40)
    y=np.exp(-x/10)
    def fit_func(x, t):
        return np.exp(-x/t)
    
    par, pcov = optimize.curve_fit(f=fit_func, xdata=x, ydata=y)
    f = fit_func(x, par)
    fig, ax = plt.subplots()
    
    left = x.min()
    section = 1
    while left < x.max():
        right = left+10
        filter = (x >= left) & (x <= right)
        ax.plot(x[filter]-left,y[filter], c='g', label="Data" if section == 1 else '')
        ax.plot(x[filter]-left, f[filter], c='r', linestyle=":", label="Fit" if section == 1 else '')
        left = right
        section += 1
    
    ax.set_xlabel("x (modulo 10)")
    ax.legend()
    #plt.savefig("fig/mod.png", dpi=300)
    plt.show()
    

    resulting plot

    Login or Signup to reply.
  2. Assuming that x is a sorted array, we’ll have :

    >>> y_ = fit_func(x, par)
    >>> temp_x = []
    >>> temp_y = []
    >>> temp_y_ = []
    >>> fig, ax = plt.subplots()
    >>> for i in range(len(x)):
        if x[i]%10==0 or i == len(x)-1:
            ax.plot(temp_x,temp_y, c='g', label="Data");
            ax.plot(temp_x,temp_y_, c='r', linestyle=":", label="Fit")
            temp_x,temp_y,temp_y_ = [],[],[]
        else:
            temp_x.append(x[i]%10)
            temp_y.append(y[i])
            temp_y_.append(y_[i])
    >>> plt.show()
    

    and this would be the resulting plot :

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search