Can I overlay a rotated histogram onto a scatter plot?

I am showing the PCA result of some data, and I hope to visualize the principal component and the secondary component of the data with two histograms (only one is shown):

I think I can achieve this by converting the histograms into images (ref: How to rotate a plotly fig). But I will lose interactivity for the histograms.

Hey @Ziyuan, welcome to the forums.

You could rotate your do a coordinate transformation do that the scatter is aligned to the x and y axis and then use rugs:

Good to know the marginal_x and marginal_y options. Do you mean to make the scatter plot and the histograms with the rotated coordinates and then rotate them back? How do I rotate the whole plot together with the axes/histograms?

Actually I am referring to switching the axis from x & y to your eigenvectors obtaind during the PCA. If Iโ€™m not mistaken, you can do something like this. Letโ€™s create some points

import numpy as np
import plotly.express as px
from sklearn.datasets import make_blobs
from sklearn.decomposition import PCA

n_samples = 1500
random_state = 170
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]

X, y = make_blobs(n_samples=n_samples, random_state=random_state)
X_aniso = np.dot(X, transformation)  # Anisotropic blobs
X_varied, y_varied = make_blobs(
    n_samples=n_samples, 
    cluster_std=[1.0, 2.5, 0.5], 
    random_state=random_state
)  

# Unequal variance
X_filtered = np.vstack(
    (
        X[y == 0][:500], 
        X[y == 1][:100], 
        X[y == 2][:10]
    )
)

# visualize points

fig = px.scatter(
    x=X_filtered[:, 0], 
    y=X_filtered[:, 1], 
    marginal_x="histogram", 
    marginal_y="histogram"
)
fig.update_layout(
    {
        'height': 500, 
        'width': 500, 
        'xaxis': {'scaleanchor':'y'}
    }
)

newplot(65)

Now do the PCA and rotate the points into the eigenvector system:

# Perform PCA on the points
pca = PCA(n_components=2)
pca.fit(X_filtered)

# Get the principal components (eigenvectors)
principal_components = pca.components_

# Rotate the original points to the principal axis
rotated_points = np.dot(X_filtered, principal_components.T)

# visialize points in the eigenvector axis system
fig = px.scatter(
    x=rotated_points[:,0], 
    y=rotated_points[:,1], 
    marginal_x="histogram", 
    marginal_y="histogram"
)
fig.update_layout(
    {
        'height': 800, 
        'width': 800, 
        'xaxis': {'title': 'Eigenvector 1','scaleanchor':'y'},
        'yaxis': {'title': 'Eigenvector 2'}
    }
)

newplot(67)

Thanks for the code. Yes, by โ€œmake the plot with the rotated coordinatesโ€, I meant with the PCA axes as you did. Do you mean there is no way to rotate the scatter plot with the histograms back? The original x and y have physical meanings in my application, so I want to keep them.

I actually dedicated some time to come up with a solution for the question asked in the topic you linked to. If I remember correctly, I tried to create a html file of the figure and then use css transforms to rotate the html in a container div.

It was still kind of interactive, but the coordinates were mixed up, so not really usable in the end.

EDIT: I played around with chatGPT, the figure is still interactive but I think you are after something else.

<!DOCTYPE html>
<html>
<head>
    <title>Main HTML File</title>
    <style>
        #parent-container {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh; /* Adjust the height of the parent container as needed */
            background-color: gray;
        }

        #rotated-frame {
            transform: rotate(-30deg);
            transform-origin: middle center;
            width: 600px; /* Adjust the width as needed */
            height: 600px; /* Adjust the height as needed */
            overflow: hidden; /* Hide scrollbars and clip the content */
            border: none; /* Remove the iframe borders */
        }
    </style>
</head>
<body>
    <div id="parent-container">
        <iframe id="rotated-frame" src="plotly_figure.html"></iframe>
    </div>
</body>
</html>

Thinking about this, I actually don`t understand what you are trying to do.

Do you want to show the Scatter Plot in physical space and the histograms in PCA space?

Yes! That was the intention. Thanks for your plots. I am now thinking about combining the content div (with points/bars) and the axis div together to get the desired plots.

Could you post the outcome here? Iโ€™d be interested to see what you come up with :raised_hands: