Scale Y axis of matplotlib plot in jupyter notebook - matplotlib

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:

Related

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()

Is there a way to draw shapes on a python pandas plot

I am creating shot plots for NHL games and I have succeeded in making the plot, but I would like to draw the lines that you see on a hockey rink on it. I basically just want to draw two circles and two lines on the plot like this.
Let me know if this is possible/how I could do it
Pandas plot is in fact matplotlib plot, you can assign it to variable and modify it according to your needs ( add horizontal and vertical lines or shapes, text, etc)
# plot your data, but instead diplaying it assing Figure and Axis to variables
fig, ax = df.plot()
ax.vlines(x, ymin, ymax, colors='k', linestyles='solid') # adjust to your needs
plt.show()
working code sample
import pandas as pd
import matplotlib.pyplot as plt
import seaborn
from matplotlib.patches import Circle
from matplotlib.collections import PatchCollection
df = seaborn.load_dataset('tips')
ax = df.plot.scatter(x='total_bill', y='tip')
ax.vlines(x=40, ymin=0, ymax=20, colors='red')
patches = [Circle((50,10), radius=3)]
collection = PatchCollection(patches, alpha=0.4)
ax.add_collection(collection)
plt.show()

plot shuffled array numpy

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.

how to draw axes passing through the origin in a 3D plot using matplotlib

I want to create a 3d plot like the following, such that axes pass through the origin with ticks on them.
PS: I could do that for 2D plots using matplotlib (the following figure). I searched a lot to do the same for 3D plots but I did not find any info.
If you want to restrict yourself to just matplotlib then we can use quiver3d plot as shown below. But the results may not be very visually appealing. You can see here how to add 3D text annotations.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.set_xlim(0,2)
ax.set_ylim(0,2)
ax.set_zlim(0,2)
ax.view_init(elev=20., azim=32)
# Make a 3D quiver plot
x, y, z = np.zeros((3,3))
u, v, w = np.array([[1,1,0],[1,0,1],[0,1,1]])
ax.quiver(x,y,z,u,v,w,arrow_length_ratio=0.1)
plt.show()

set the distance between ticks in gridspec

I am trying to draw two 1-d series on top of each other, meaning, without any vertical spacing and I use subplot2grid as I have multiple subplots. The code below alines the lines to top most and bottom most. how can I draw adjacent lines?
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.figure
import matplotlib.gridspec as gridspec
ax = plt.subplot2grid((1, 1), (0,0))
xvalues = range(0,10)
yvalues = np.ones_like(xvalues)
ax.scatter(xvalues, yvalues)
ax.scatter(xvalues, np.add(yvalues, 1))
ax.set_yticks([1,2])
plt.tight_layout()
plt.show()
The gap between the groups of points is due to the fact that matplotlib autoscales the plot to have 5 percent of the difference between the minimum and maximum point on the axes as padding on each side. If minimum is 1 and maximum is 2, the plot hence ranges from ~0.95 to ~2.05.
Of course you can change the limits, e.g.
ax.set_ylim(-5,8)
would produce a plot like