Warping Matplotlib/Seaborn Scatter Plot into Parallelogram - matplotlib

I have a 2D scatterplot (in either matplotlib or seaborn) and an angle e.g. 64 degrees. I want to plot a warped version of this scatter plot where the x-axis of the first plot is held fixed but the second axis is warped such that the y-axis of the first plot is now at the given angle with the x-axis of the new plot (i.e. 64 degrees). How can I do this?
In other words, I want to take the original scatter plot and "push" the y-axis to the right to form a parallelogram-like plot where the angle between the old y axis and the old/new x-axis is the given angle.

Here is an adaption of an old tutorial example:
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
import numpy as np
fig = plt.figure()
skewed_transform = Affine2D().skew_deg(90 - 64, 0)
grid_helper = floating_axes.GridHelperCurveLinear(skewed_transform, extremes=(-0.5, 1.5, -0.5, 1.5))
skewed_ax = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper)
skewed_ax.set_facecolor('0.95') # light grey background
skewed_ax.axis["top"].set_visible(False)
skewed_ax.axis["right"].set_visible(False)
fig.add_subplot(skewed_ax)
x, y = np.random.rand(2, 100) # random point in a square of [0,1]x[0,1]
skewed_ax.scatter(x, y, transform=skewed_transform + skewed_ax.transData)
plt.show()

Related

Matplotlib time series graph with 3 Y-Axes on right side of graph

I am using matplotlib to graph 3 time series. I want all 3 y-axes to be plotted on the right side of the graph. However I am unable to get one of the y-axis values to plot on the right side, only it's axis label.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import datetime as dt
import matplotlib.dates as mdates
from matplotlib.ticker import ScalarFormatter, FormatStrFormatter
from matplotlib import ticker
# Set date range for graph
df_ratios=df_ratios.loc['2017-06':'2021-12']
#-------------------------------------------------------------------
#For all Matplotlib plots, we start by creating a figure and an axes.
#-------------------------------------------------------------------
# subplot for plotting figure
fig, ax = plt.subplots()
#Similar to fig=plt.figure(figsize=(12,6))
fig.set_figwidth(12)
fig.set_figheight(6)
# Graph title
#############
fig.suptitle('Inventory-to-Sales Ratios by Industry',fontsize=20)
# LABELS: Set x label which is common / set left y-axis label / set labelcolor and labelsize to the left Y-axis
###############################################################################################################
ax.set_xlabel('Monthly: Jun 2017 - Dec. 2021')
ax.set_ylabel('Manufacturers I/S Ratio', color='red',size='x-large')
ax.tick_params(axis='y', labelcolor='red', labelsize='large')
ax.spines["right"].set_visible(True)
# Left Y-Axis: Mfg IS ratio on left Y-axis
###########################################
ax.plot(df_ratios.index, df_ratios['mfg_is_ratio'], color='red',linewidth=5.0)
ax.set_ylim(1.25,1.8)
ax.yaxis.set_major_locator(ticker.MultipleLocator(0.10))
ax.yaxis.set_label_position('right')
ax.yaxis.set_ticks_position('right')
ax.spines["right"].set_position(("axes", 1.0)) # Set second Y-axis 10% away from existing Y axis
# RIGHT Y-Axis labels: twinx sets the same x-axis for both plots / set right y-axis label / set labelcolor and labelsize to the right Y-axis
############################################################################################################################################
ax_1 = ax.twinx()
ax_1.set_ylabel('Wholesalers I/S Ratio', color='blue', size='x-large')
ax_1.tick_params(axis='y', labelcolor='blue',labelsize='large')
# FIRST Right Y-Axis plot: Wholesale IS ratio
#############################################
ax_1.plot(df_ratios.index, df_ratios['whole_is_ratio'], color='blue',linewidth=5.0)
ax_1.spines["right"].set_position(("axes", 1.08)) # Set second Y-axis 10% away from existing Y axis
ax_1.set_ylim(1.15,1.75)
ax_1.yaxis.set_major_locator(ticker.MultipleLocator(0.10))
# SECOND Right Y-Axis: Sum of Mfg+Wholesale ratios
##################################################
ax_2=ax.twinx()
ax_2.set_ylabel('Wholesalers Inventories', color='green', size='x-large')
ax_2.spines["right"].set_position(("axes", 1.18)) # Set second Y-axis 10% away from existing Y axis
ax_2.set_ylim(2.60,3.25)
ax_2.plot(df_ratios.index, df_ratios['totals'], color='green',linewidth=5.0)
ax_2.tick_params(axis='y', labelcolor='green',labelsize='large')
# Show graph:
#############
plt.show()
Here is the result:
How do I get the red y-axis values (manufacturers i/s ratio) to plot on the right side of the graph?
The problem is, when twinx() is used.
From the source code documentation:
Create a new Axes with an invisible x-axis and an independent y-axis
positioned opposite to the original one (i.e. at right).
To reverse this, just use ax.yaxis.tick_right() after all twinx() calls.
For example right before plt.show().
Red ticks should be now placed on the right side.

plot_surface reduces density of points

Trying to plot a surface using matplotlib. However, the plotted surface has lower grid density than the meshgrid.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
xgrid = np.arange(0,1,1/100)
ygrid = xgrid.copy()
xx, yy = np.meshgrid(xgrid,ygrid)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(xx,yy,np.square(xx)+np.square(yy))
The meshgrid was defined to have 100 segments in each direction. However, the surface in the figure doesn't have 100 segments. Is there anyway to render the surface with the same density?
Don't worry, you don't have to count the number of segments, so I overlap the plot with a scatter plot with the same points
ax.scatter3D(xx,yy,np.square(xx)+np.square(yy))
Upon zooming in, you can see that each grid of the surface plot has a scatter point in the middle, which shows that the plot_surface changed the density of the points.
Usually it doesn't matter for smooth plots such as these, but I have singular points in my data which sometimes disappear in the surface plot because of this

Is it possible to do draw plot in matplotlib where all points are linked to the x axis?

I am trying to find a way in matplotlib to draw a lineplot, except that I don't want to draw a line between points. Instead I want to draw a perpendicular line between each of my points and the x axis.
When I do a standard plot, I obtain the following :
import numpy as np
import matplotlib.pyplot as plt
data = np.array([0,1,3,2,3,1,4])
plt.plot(data)
plt.xlim([-0.2,6.2])
plt.ylim([-0.2,5])
Instead I want to obtain the following :
Any ideas how to do this ?
Thanks
There are two other options apart from stem and bar chart is the following using vlines() and LineCollection()
Option 1 -- Using vlines()
for x, y in enumerate(data):
plt.vlines(x=x, ymin=0, ymax=y, color='r')
Or in a single line without using loops
plt.vlines(x=range(data.size), ymin=0, ymax=data, color='r')
Option 2 -- Using LineCollection()
from matplotlib.collections import LineCollection
lines = [[(x, 0), (x, y)] for x, y in enumerate(data)]
linesCol = LineCollection(lines, linewidths=3, color='r')
fig, ax = plt.subplots()
ax.add_collection(linesCol)
plt.scatter(range(len(data)), data, s=0)

How to overlay one pyplot figure on another

Searching easily reveals how to plot multiple charts on one figure, whether using the same plotting axes, a second y axis or subplots. Much harder to uncover is how to overlay one figure onto another, something like this:
That image was prepared using a bitmap editor to overlay the images. I have no difficulty creating the individual plots, but cannot figure out how to combine them. I expect a single line of code will suffice, but what is it? Here is how I imagine it:
bigFig = plt.figure(1, figsize=[5,25])
...
ltlFig = plt.figure(2)
...
bigFig.overlay(ltlFig, pos=[x,y], size=[1,1])
I've established that I can use figure.add_axes, but it is quite challenging getting the position of the overlaid plot correct, since the parameters are fractions, not x,y values from the first plot. It also [it seems to me - am I wrong?] places constraints on the order in which the charts are plotted, since the main plot must be completed before the other plots are added in turn.
What is the pyplot method that achieves this?
To create an inset axes you may use mpl_toolkits.axes_grid1.inset_locator.inset_axes.
Position of inset axes in axes coordinates
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
fig, ax= plt.subplots()
inset_axes = inset_axes(ax,
width=1, # inch
height=1, # inch
bbox_transform=ax.transAxes, # relative axes coordinates
bbox_to_anchor=(0.5,0.5), # relative axes coordinates
loc=3) # loc=lower left corner
ax.axis([0,500,-.1,.1])
plt.show()
Position of inset axes in data coordinates
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
fig, ax= plt.subplots()
inset_axes = inset_axes(ax,
width=1, # inch
height=1, # inch
bbox_transform=ax.transData, # data coordinates
bbox_to_anchor=(250,0.0), # data coordinates
loc=3) # loc=lower left corner
ax.axis([0,500,-.1,.1])
plt.show()
Both of the above produce the same plot
(For a possible drawback of this solution see specific location for inset axes)

Creating a 1D heat map from a line graph

Is it possible to create a 1D heat map from data in a line graph? i.e. I'd like the highest values in y to represent the warmer colours in a heat map. I've attached an example image of the heat map I'd like it to look like as well as data I currently have in the line graph.
1D heat map and graph example:
To get the heatmap in the image shown I used the following code in python with matplotlib.pyplot:
heatmap, xedges, yedges = np.histogram2d(x, y, bins=(np.linspace(0,length_track,length_track+1),1))
extent = [0, length_track+1, 0, 50]
plt.imshow(heatmap.T, extent=extent, origin='lower', cmap='jet',vmin=0,vmax=None)
But I believe this only works if the data is represented as a scatter plot.
If we assume that the data is equally spaced, one may use an imshow plot to recreate the plot from the question.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
plt.rcParams["figure.figsize"] = 5,2
x = np.linspace(-3,3)
y = np.cumsum(np.random.randn(50))+6
fig, (ax,ax2) = plt.subplots(nrows=2, sharex=True)
extent = [x[0]-(x[1]-x[0])/2., x[-1]+(x[1]-x[0])/2.,0,1]
ax.imshow(y[np.newaxis,:], cmap="plasma", aspect="auto", extent=extent)
ax.set_yticks([])
ax.set_xlim(extent[0], extent[1])
ax2.plot(x,y)
plt.tight_layout()
plt.show()