erdogant / pca

pca: A Python Package for Principal Component Analysis.
https://erdogant.github.io/pca
MIT License
284 stars 42 forks source link

Feature request: use helper function approach for plotting #39

Closed koutoftimer closed 1 year ago

koutoftimer commented 1 year ago

Problem

The only way to nest figures is via helper function as stated in Matplotlib Quickstart.

Current implementation requires monkey patching matplotlib before binplot call if one would like to have several subplots on the figure.

Workaround

@contextmanager
def monkey_patched_figure_and_subplot(fig: plt.Figure, ax: plt.Axes):
    old_figure = plt.figure
    old_add_subplot = fig.add_subplot

    def new_figure(*args, **kwargs):
        return fig

    def new_add_subplot(*args, **kwargs):
        return ax

    plt.figure = new_figure
    fig.add_subplot = new_add_subplot

    yield

    plt.figure = old_figure
    fig.add_subplot = old_add_subplot

...

model = pca(n_components=2)
model.fit_transform(data)
with monkey_patched_figure_and_subplot(fig, ax):
    model.biplot()

Suggestion

Allow to pass ax and fig to binplot and other methods.

tacaswell commented 1 year ago

Adding the ability to pass an Axes into biplot may be simpler to implement and use.

erdogant commented 1 year ago

True. Please send a pull request or otherwise I will look into it but it may take some time.

erdogant commented 1 year ago

I implemented an optional parameter for fig. Before releasing, do you want to give it a try whether it works as expected? You can install from github source as following (version should be 1.8.6):

pip install git+https://github.com/erdogant/pca

from sklearn.datasets import make_friedman1
X, _ = make_friedman1(n_samples=200, n_features=30, random_state=0)

# Init
model = pca()

# Fit
model.fit_transform(X)

# Make plot with some parameters
fig, ax = model.biplot(fontdict={'size':10, 'weight':'normal'}, title=None, SPE=False, hotellingt2=True, n_feat=10, visible=False)

# Use the existing fig and create new edits such as different fontsize and title and SPE=True
fig, ax = model.biplot(fontdict={'size':16, 'weight':'bold'}, SPE=True, n_feat=3, fig=fig, visible=True, title='updated fig.')
koutoftimer commented 1 year ago
  1. I have failed to install this library into anaconda environment, that is why I'm not longer interested in it. Perhaps I'm just not familiar enough with it.
  2. My use case without pca library looks like this
fig, axs = plt.subplots(nrows=2, ncols=2)
for ax, values in zip(axs.flatten(), groups):
    draw_figure(ax, values)

main layout is 2x2. By passing figure only, right now, there is no way to specify "layout". That is why I'm patching both fig and ax to maintain layout outside of pca library and just tell it where I want figure to be drawn. Also I had to support multiple layouts but ax = fig.axes[0] makes suggestion about what layout should be like. When I was working on fork solution I used following logic: provide both fig and ax or let library to decide. This prevents a lot of corner cases.

erdogant commented 1 year ago

I created updates to add fig as input parameter to the biplot. Here is an example.

Update to the latest version with: pip install -U pca

erdogant commented 1 year ago

closing this one. Let me know if something is still missing.