0

I am trying to plot a smooth line graph in matplotlib with a discrete x-axis that are strings (please see output figure below). I am currently getting jagged lines. All the examples, I have seen on Stack Overflow deal with a continuous x-axis (example), and rely on leveraging the x-axis for linspace() or spline from scipy.interpolate. Here is a excerpt of the plotting code that gives the jagged lines:

xstrings = ['Q2W1','Q2W2','Q2W3','Q2W4','Q2W5','Q2W6','Q2W7','Q2W8','Q2W9','Q2W10','Q2QW11','Q2W12','Q2W13']
y = [88,84,83,99,96,85,85,82,65,60,19,45,27]


plt.plot(xstrings, y, linestyle='-', marker='.', color='#009d9a', linewidth=1)
#plt.legend(['data', 'linear', 'cubic'], loc='best')

for a,b in zip(xstrings,y):
   xs.append(a)
   ys.append(b)
   if b < 7:
       label = "${:,.2f}".format(b)
   elif b < 10:
       label = "${:,.1f}".format(b)
   else:
       label = "${:,.0f}".format(b)
   plt.annotate(label, # this is the text
                (a,b), # this is the point to label
                textcoords="offset points", # how to position the text
                xytext=(0,3), # distance from text to points (x,y)
                ha='center', fontsize = 6)


plt.xticks(fontsize=6.5, rotation=45)
plt.show()
plt.savefig("Graphs/"+'test.png', dpi=300, bbox_inches='tight')

Here is the output: enter image description here

I am expecting the output to look something like this (on the right) post-smoothing but my x-axis is a string: enter image description here

Any help with this would be appreciated !

Shashank
  • 55
  • 7
  • So, what are you after here? Are you hoping to do line-fitting or curve-fitting to your existing points? Do you just want to get rid of the individual dots? – Tim Roberts Jul 04 '21 at 04:22
  • I want to keep the individual dots but I want the line to be curved and smooth rather than linear and rough. So perhaps curve-fitting is the answer here, but a curve that goes through all the points. – Shashank Jul 04 '21 at 04:25
  • 2
    But your data is not curved and smooth Your data is disjoint. Adding curvature is misrepresenting the data set. – Tim Roberts Jul 04 '21 at 04:28
  • I have added the an example expected output for more clarity, if that helps – Shashank Jul 04 '21 at 04:34
  • 1
    The scipy spline should do what you want. This example starts with discrete data: https://stackoverflow.com/questions/5283649/plot-smooth-line-with-pyplot – Tim Roberts Jul 04 '21 at 04:37
  • Thats the first link I went to: they are using linspace for the x-axis and inputting that to spline, and the use of gaussian function changes the numbers. Is there an example you are specifically referring to? My x-axis is letters+numbers – Shashank Jul 04 '21 at 05:09

1 Answers1

0

The example code literally copied from SciPy's interpolate module documentation:

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

x = np.linspace(0, 10, num=11, endpoint=True)
y = np.cos(-x**2/9.0)

f = interp1d(x, y)
f2 = interp1d(x, y, kind='cubic')

xnew = np.linspace(0, 10, num=41, endpoint=True)

plt.plot(x, y, 'o', xnew, f(xnew), '-', xnew, f2(xnew), '--')
plt.legend(['data', 'linear', 'cubic'], loc='best')
plt.show()

This produces:

enter image description here

More information is in the documentation of scipy.interpolate.interp1d.

Let me add that you do misrepresent the data by such plot as was mentioned in comments. You do add the information to the original data. The justifiable action would be linear interpolation (np.polyfit with deg=1) or moving average.

Roman Pavelka
  • 3,736
  • 2
  • 11
  • 28
  • Thanks for this Roman - this again uses an x-axis that is an integer and linear. My x-axis is a string. I believe neither interp1d not polyfit work for that – Shashank Jul 04 '21 at 19:01
  • 1
    An x-axis of strings, is internally numbered `0,1,2,3,....`. You can set the strings via e.g. `plt.xticks(np.arange(len(xstrings)), xstrings)` where `xstrings = ['str1', 'str2', ....]`. – JohanC Jul 04 '21 at 21:19
  • @Shashank, as the data are equidistant, it will work. – Roman Pavelka Jul 05 '21 at 14:15