plot shuffled array numpy - matplotlib

I am writting a very simple script, one that plot a sin using jupyter notebook (python 3). when I put:
import numpy
import matplotlib.pyplot as plt
x=np.arange(0.0,5*np.pi,0.001)
y = np.sin(x)
plt.plot(x,y)
The plot is fine.
However if :
import numpy
import matplotlib.pyplot as plt
x=np.arange(0.0,5*np.pi,0.001)
np.random.shuffle(x)
y = np.sin(x)
plt.plot(x,y)
the image is
I don't understand why shuffling the x BEFORE I ran sin does it.
thank you

Let's first simplify things a bit. We plot 4 points and annote them with the order in which they are plotted.
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
x=np.arange(4)
y = np.sin(x)
plt.plot(x,y, marker="o")
for i, (xi,yi) in enumerate(zip(x,y)):
plt.annotate(str(i), xy=(xi,yi), xytext=(0,4),
textcoords="offset points", ha="center")
plt.show()
No if we shuffle x and plot the same graph,
x=np.arange(4)
np.random.shuffle(x)
y = np.sin(x)
we see that positions of the points are still are the same, but while e.g. previously the first point was the one at (0,0), it's now the third one appearing there. Due to this randomized order, the connecting lines go zickzack.
Now if you use enough points, all those lines will add up to look like a complete surface, which is what you get in your image.

Related

How to get any kind of interactive plot with ipywidgets and matplotlib

I am just looking for some kind of working example which will allow me to have a slider and a sine wave plot whereby I can vary the frequency in a Jupyter Notebook. All the online demos that I have Googled don't work for me. The issue seems to be that the old matplotlib graph is not erased before the new one is created.
Here is my minimal example
import ipywidgets as widgets
from IPython.display import display, clear_output
import matplotlib.pyplot as plt
import numpy as np
def f(a):
clear_output(wait=True)
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(a*x)
ax.grid()
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.plot(x,y)
ax.set_title("y = sin(x)")
%matplotlib inline
from time import sleep
for i in range(1,10):
clear_output(wait=True)
f(i)
sleep(1)
I have also tried
out = widgets.Output(layout={'border': '1px solid black'})
with out:
widgets.interact(f, a=1)
out.clear_output()
display(out)
However nothing I try will erase the previous matplotlib graph. They just all pile up on top of each other. I admit I am floundering as I don't really understand the API that well and the example in the documentation don't work for me.
I don't expect people to fix my code as it is probably rubbish. I am just looking for a working example which will allow me to interactively control the frequency and redraw the sine wave on a Jupyter notebook.
Here is a minimal example that works for me:
from ipywidgets import interact
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
def plot(freq):
x = np.linspace(0, 2*np.pi)
y = np.sin(x * freq)
plt.plot(x, y)
interact(plot, freq = widgets.FloatSlider(value=2, min=0.1, max=5, step=0.1))
default plot:
Screenshot of notebook after moving the slider to the right:

transform the values of one axis to its log

I'm trying to transform the scales on y-axis to the log values. For example, if one of the numbers on y is 0.01, I want to get -2 (which is log(0.01)). How should I do this in matplotlib (or any other library)?!
Thanks,
Without plt.yscale('log') there will be few y-ticks visible that have a nice number as log. You can change the "formatter" to a function that only shows the exponent. Also note that in the latest seaborn version distplot has been replaced by histplot(..., kde=True) or kdeplot(...).
Here is an example:
import matplotlib.pyplot as plt
from matplotlib.ticker import LogFormatterExponent
import numpy as np
import seaborn as sns
x = np.random.randn(10, 1000).cumsum(axis=1).ravel()
ax = sns.histplot(x, kde=True, stat='density', color='purple')
ax.set_yscale('log')
ax.yaxis.set_major_formatter(LogFormatterExponent(base=10.0, labelOnlyBase=True))
ax.set_ylabel(ax.get_ylabel() + ' (exponent)')
ax.margins(x=0)
plt.show()

Scale Y axis of matplotlib plot in jupyter notebook

I want to scale Y axis so that I can see values, as code below plots cant see anything other than a thin black line. Changing plot height doesn't expand the plot.
import numpy as np
import matplotlib.pyplot as plt
data=np.random.random((4,10000))
plt.rcParams["figure.figsize"] = (20,100)
#or swap line above with one below, still no change in plot height
#fig=plt.figure(figsize=(20, 100))
plt.matshow(data)
plt.show()
One way to do this is just repeat the values then plot result, but I would have thought it possible to just scale the height of the plot?
data_repeated = np.repeat(data, repeats=1000, axis=0)
You can do it like this:
import numpy as np
import matplotlib.pyplot as plt
data=np.random.random((4, 10000))
plt.figure(figsize=(40, 10))
plt.matshow(data, fignum=1, aspect='auto')
plt.show()
Output:

Graph Line Parallel to X Axis in Matplotlib

I'm thinking this is extremely simple. I would like to graph the line y = 7.87. This graphs a line parallel to the y-axis, but I'm looking for something horizontal, parallel with x-axis. Any ideas?
import matplotlib.pyplot as plt
plt.axvline(x = 7.85)
plt.show()
It really is quite simple:
import matplotlib.pyplot as plt
plt.axhline(y=7.87)
plt.show()
The h and v in the function names (axhline and axvline) stand for horizontal and vertical.

Tick labels displaying outside axis limits

Is there a way to automatically not display tick mark labels if they would protrude past the axis itself? For example, consider the following code
#!/usr/bin/python
import pylab as P, numpy as N, math as M
xvals=N.arange(-10,10,0.1)
yvals=[ M.sin(x) for x in xvals ]
P.plot( xvals, yvals )
P.show()
See how the -10 and 10 labels on the x-axis poke out to the left and right of the plot? And similar for the -1.0 and 1.0 labels on the y-axis. Can I automatically suppress plotting these but retain the ones that do not go outside the plot limits?
I think you could just format the axis ticks yourself and then prune the ones
that are hanging over. The recommended way to deal with setting up the axis is
to use the ticker API. So for example
from matplotlib.ticker import MaxNLocator
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
xvals=np.arange(-10,10,0.1)
yvals=[ np.sin(x) for x in xvals ]
ax.plot( xvals, yvals )
ax.xaxis.set_major_locator(MaxNLocator(prune='both'))
plt.show()
Here we are creating a figure and axes, plotting the data, and then setting the xaxis
major ticks. The formatter MaxNLocator is given the
argument prune='both' which is described in the docs here.
This is not exactly what you were asking for, but maybe it will solve your problem.