set the distance between ticks in gridspec - matplotlib

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

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

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:

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

changing the size of subplots with matplotlib

I am trying to plot multiple rgb images with matplotlib
the code I am using is:
import numpy as np
import matplotlib.pyplot as plt
for i in range(0, images):
test = np.random.rand(1080, 720,3)
plt.subplot(images,2,i+1)
plt.imshow(test, interpolation='none')
the subplots appear tiny though as thumbnails
How can I make them bigger?
I have seen solutions using
fig, ax = plt.subplots()
syntax before but not with plt.subplot ?
plt.subplots initiates a subplot grid, while plt.subplot adds a subplot. So the difference is whether you want to initiate you plot right away or fill it over time. Since it seems, that you know how many images to plot beforehand, I would also recommend going with subplots.
Also notice, that the way you use plt.subplot you generate empy subplots in between the ones you are actually using, which is another reason they are so small.
import numpy as np
import matplotlib.pyplot as plt
images = 4
fig, axes = plt.subplots(images, 1, # Puts subplots in the axes variable
figsize=(4, 10), # Use figsize to set the size of the whole plot
dpi=200, # Further refine size with dpi setting
tight_layout=True) # Makes enough room between plots for labels
for i, ax in enumerate(axes):
y = np.random.randn(512, 512)
ax.imshow(y)
ax.set_title(str(i), fontweight='bold')

How to fully customize subplot size in matplotlib

I want to have two subplots in a matplotlib figure that are sized and positioned relative to each other like the example below (for stylistic reasons). All the examples I've seen for customizing subplot placement and sizes still tile and fill the entire figure footprint. What can I do to get the rightmost plot positioned with some whitespace like below?
You need to imagine some (virtual) grid on which the subplots are placed.
The grid has 3 rows and 2 columns. The first subplot covers all three rows and the first column. The second subplot covers only the second row of the second column. The ratios between the row and column sizes are not necessarily equal.
import matplotlib.pyplot as plt
import matplotlib.gridspec
gs = matplotlib.gridspec.GridSpec(3,2, width_ratios=[1,1.4],
height_ratios=[1,3,1])
fig = plt.figure()
ax1 = fig.add_subplot(gs[:,0])
ax2 = fig.add_subplot(gs[1,1])
plt.show()
In addition you may still set different values to hspace and wspace parameters.
A good overview is given in the GridSpec tutorial.
Because it was mentionned in the comments: If absolute positionning in units of inches may be desired, I would recommend directly adding an axes in the desired size,
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
w,h = fig.get_size_inches()
div = np.array([w,h,w,h])
# define axes in by rectangle [left, bottom, width, height], numbers in inches
ax1 = fig.add_axes(np.array([.7, .7, 1.8, 3.4])/div)
ax2 = fig.add_axes(np.array([3, 1.4, 3, 2])/div)
plt.show()
--EDIT: This answer ended up startlingly similar to the answer given by #ImportanceOfBeingErnest but tacks on an approach for layout control in inches units rather than fractional units. --
It helps if you grid it out with gridspec, and then populate the grid using the desired spans of the ratios or columns. For a lot of the figures I make I need them to fit on the page well, so I use this pattern pretty frequently to give me grid control down to the 10th of an inch.
import matplotlib.pyplot as plt
from matplotlib import gridspec
fig = plt.figure(figsize=(7, 5)) # 7 inches wide, 5 inches tall
row = int(fig.get_figheight() * 10)
col = int(fig.get_figwidth() * 10)
gsfig = gridspec.GridSpec(
row, col,
left=0, right=1, bottom=0,
top=1, wspace=0, hspace=0)
gs1 = gsfig[:, 0:30]
# these spans are in tenths of an inch, so left-right
# spans from col 0 to column 30 (or 3 inches)
ax1 = fig.add_subplot(gs1)
gs1 = gsfig[20:40, 35:70] # again these spans are in tenths of an inch
ax1 = fig.add_subplot(gs1)