Git Product home page Git Product logo

Comments (12)

amueller avatar amueller commented on July 30, 2024 1

beautiful
image

from dabl.

amueller avatar amueller commented on July 30, 2024

good to have around at least ;)

from dabl.

thomasjpfan avatar thomasjpfan commented on July 30, 2024

Another way to generate the same plot with make_axes_locatable:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

rs = np.random.RandomState(42)
x1, x2 = rs.multivariate_normal([0, 0], [(1, 0.5), (0.5, 1)], 500).T

fig, ax = plt.subplots(figsize=(6, 6))
ax.scatter(x1, x2, alpha=0.6)

divier = make_axes_locatable(ax)
ax_hist_x1 = divier.append_axes("top", size=1.2, pad=0, sharex=ax)
ax_hist_x2 = divier.append_axes("right", size=1.2, pad=0, sharey=ax)

ax_hist_x1.hist(x1, bins=30)
ax_hist_x1.set_axis_off()

ax_hist_x2.hist(x1, bins=30, orientation='horizontal');
ax_hist_x2.set_axis_off()

The AxesGrid toolkit has some randomly useful stuff.

Edit: Although it may not be as useful: DistrictDataLabs/yellowbrick#826 (comment)

from dabl.

thomasjpfan avatar thomasjpfan commented on July 30, 2024

This does the "pass an single axes and plot multiple things in that region" idea:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

def plot_scatter(x1, x2, ax=None):
    if ax is None:
        ax = plt.gca()
        
    # create gridspec
    gs = gridspec.GridSpecFromSubplotSpec(2, 2, 
                                          subplot_spec=ax.get_subplotspec(),
                                          width_ratios=[4, 1],
                                          height_ratios=[1, 4],
                                          hspace=0, wspace=0)
    ax.set_subplotspec(gs[2])
    ax.update_params()
    ax.set_position(ax.figbox)
    ax.scatter(x1, x2)
    
    fig = ax.get_figure()
    top_ax = fig.add_subplot(gs[0])
    top_ax.hist(x1, bins=30)
    top_ax.set_axis_off()
    
    right_ax = fig.add_subplot(gs[3])
    right_ax.hist(x2, bins=30, orientation='horizontal')
    right_ax.set_axis_off()
    
rs = np.random.RandomState(42)
x1, x2, = rs.multivariate_normal([0, 0], [(1, 0.5), (0.5, 1)], 500).T
fig, ax = plt.subplots(figsize=(8, 8))
plot_scatter(x1, x2, ax=ax)

from dabl.

amueller avatar amueller commented on July 30, 2024

The last one seems to work nicely:

from sklearn.datasets import load_iris
iris = load_iris()

import itertools
fig, axes = plt.subplots(4, 4, figsize=(10, 10))
for i, j in itertools.product(range(4), repeat=2):
    plot_scatter(iris.data[:, i], iris.data[:, j], ax=axes[i, j])

image

Though trying to modify the axes is a bit tricky, say you want to set at title:

fig, axes = plt.subplots(4, 4, figsize=(10, 10))
for i, j in itertools.product(range(4), repeat=2):
    plot_scatter(iris.data[:, i], iris.data[:, j], ax=axes[i, j])
    axes[i, j].set_title("some title")

image

from dabl.

amueller avatar amueller commented on July 30, 2024

Ok so you already kind of implemented it in as "smart" way so that the scatter plot is the original axis. That means some things work and others don't. For example if I want to hide the diagonal, I'll only hide the scatter plot axes.

If the plotting function returns the three axes, I can do most things that I want, though.
A slightly more crazy thing would be to have the plotting function return a new object that has some of the same methods as the axes but "does the right thing". For example I want to set the title by setting the title on the top axis. If I set visible I want all of them to disappear etc. Maybe that's a bit overkill for now and we can just return the three axis.

Did you write down the three usage scenarios we discussed? I think you just solved one of them.

from dabl.

amueller avatar amueller commented on July 30, 2024

Actually, I think this might solve all of them? That would be cool. But I don't remember all of them ;)

from dabl.

amueller avatar amueller commented on July 30, 2024

using constrained_layout=True kills my jupyter kernel ...

terminate called after throwing an instance of 'kiwi::InternalSolverError'
  what():  Dual optimize failed.

I feel a more graceful failure would be nice

from dabl.

thomasjpfan avatar thomasjpfan commented on July 30, 2024

The way this moves axes around will segfault with constrained_layout. There is a way to check for this (fig.get_constrained_layout()) and error nicely.

Edit: constrained_layout is experimental.

from dabl.

thomasjpfan avatar thomasjpfan commented on July 30, 2024

Three use cases

  1. Internal Layout is fixed - KDF plot
  2. Layout depends on parameters - Partial dependence plot
  3. Plotting the same thing for different models on the same axes - Calibration Curves

from dabl.

amueller avatar amueller commented on July 30, 2024
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

fig, axes = plt.subplots(3, 2, constrained_layout=True)
ax = axes[0, 0]
        
# create gridspec
gs = gridspec.GridSpecFromSubplotSpec(
    2, 2, subplot_spec=ax.get_subplotspec())

ax.set_subplotspec(gs[2])

kills the kernel.
This is not a segfault, it's a purposeful exit on part of the solver, I'm pretty sure.

from dabl.

amueller avatar amueller commented on July 30, 2024

Coming back to the use cases:

  1. is solved in a mostly obvious way: we provide one axis and the plotting functions steals from the space. Only potential issue is the user trying to modify the axes afterwards.

  2. we said the user can provide axes and if the length doesn't match we raise an error.

  3. is not solved by the above method for compound axes.

Possible solution to 3: have the plotting function return a custom object (that kind of was our plan all along anyway, right?) and then allow the user to pass one of these into the function instead of the axes.

An obvious question then is whether we allow users to also pass an object into the plotting function for use-case 2. I don't entirely see why not, but I'm also not sure if it's necessary.

So functions either take a single axis or a plot object (and potentially create multiple axes internally), or multiple axes (and plot object not allowed?).

This would be somewhat restrictive in that we'd only allow CallibrationPlot objects to be passed into the plot_callibration function but I think that makes sense. If the user wants to do something extra special they can still access the axes manually.

from dabl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.