<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Advanced
Step1:  Top-level distl distribution creation functions
PHOEBE includes distl as a built-in dependency to handle creating and manipulating distribution objects.  The following distribution creation-functions are available from the top-level of PHOEBE (i.e. distributions are created by calling phoebe.gaussian(...), etc)
Step2:  Note that, when passing a distribution object to b.add_distribution, the values of unit, label, label_latex, and wrap_at will be handled by PHOEBE itself - based on the parameter to which the distribution is attached.
To learn more about manipulating distribution objects before calling b.add_distribution, see the distl docs.
Let's create a distl gaussian distribution and then attach it to a parameter in PHOEBE.
Step3:  Note that since we didn't provide label or unit, those will be missing when plotting the distribution object.
Step4:  However, b.add_distribution will populate unit and wrap_at (when applicable)
Step5:  And whenever plotting through b.plot_distribution_collection or b.plot, the latex representation of the respective parameters will be included.
Step6:  "Around" distributions
If we look at the API docs for gaussian and gaussian_around, we'll notice that they're essentially the same, except that gaussian_around does not require the first loc argument.
Step7:  When attached in PHOEBE, any "around" distribution will have its central value updated to always be that of the current parameter value to which its attached.  This can be very convenient in some cases (for example, setting init_from to always be an N-dimensional Gaussian "ball" around the current values), but in other cases is not appropriate (for priors, where any attached distribution should be based on external knowledge or assumptions, and therefore should be fixed and not update with changing parameter values).
Now we'll attach both a gaussian and gaussian_around distribution and see how they behave differently.
Step8:  Since the central value is currently 6000, these two distributions are currently identical (the value in the gaussian_around is the current value that will be adopted as loc whenever the distribution is actually used).
Step9:  However, if we change the parameter value, we can see that the "around" distribution updates its central value accordingly.
Step10:  Note that if we try to use any distribution-set with an "around" distribution as priors in a solver, a warning will be raised (as of PHOEBE 2.3.23).
Similar to gaussian and gaussian_around, uniform takes a lower and upper bound, whereas uniform_around only takes a width, with the central value adopted from the current face-value.
Step11:  Multivariate distributions
Multivariate distributions allow for storing the covariance between the distributions of multiple parameters.  Although the creation functions are exposed at the top-level, these are most seen in PHOEBE after running an MCMC chain.  For more information on manipulating these multivariate posteriors, see Advanced
Step12:  Once we create our single distl multivariate object, we then need to tell PHOEBE which "slices" of that multivariate distribution to attach to which parameters.
Here we will set labels, just to make it easier to track the dimensions of the distribution object.
Step13:  By calling dist.slice, we get a distl object which retains the covariance matrix, but represents a single dimension, which can then be passed to PHOEBE.
Step14:  And we can see that the covariances (although stored three separate times) are maintained whenever sampling from the distributions within PHOEBE.
<ASSISTANT_TASK:>
Python Code:
#!pip install -I "phoebe>=2.3,<2.4"
import phoebe
from phoebe import u # units
import numpy as np
logger = phoebe.logger()
b = phoebe.default_binary()
Explanation: Advanced: Distribution Types
Setup
Let's first make sure we have the latest version of PHOEBE 2.3 installed (uncomment this line if running in an online notebook session such as colab).
End of explanation
help(phoebe.gaussian)
Explanation: Top-level distl distribution creation functions
PHOEBE includes distl as a built-in dependency to handle creating and manipulating distribution objects.  The following distribution creation-functions are available from the top-level of PHOEBE (i.e. distributions are created by calling phoebe.gaussian(...), etc):
gaussian
gaussian_around
histogram_from_bins
histogram_from_data
mvgaussian
mvhistogram_from_data
uniform
uniform_around
The distinction between gaussian and gaussian_around as well as uniform and uniform_around will be discussed in more detail in the next section.  Following that, multivariate distributions (those starting with mv) will be introduced.
To see the arguments to any of these creation functions, follow the links above to the respective API docs, or call help on the method.
End of explanation
dist = phoebe.gaussian(6000, 100)
print(dist)
Explanation: Note that, when passing a distribution object to b.add_distribution, the values of unit, label, label_latex, and wrap_at will be handled by PHOEBE itself - based on the parameter to which the distribution is attached.
To learn more about manipulating distribution objects before calling b.add_distribution, see the distl docs.
Let's create a distl gaussian distribution and then attach it to a parameter in PHOEBE.
End of explanation
_ = dist.plot(show=True)
Explanation: Note that since we didn't provide label or unit, those will be missing when plotting the distribution object.
End of explanation
b.add_distribution('teff@primary', dist, distribution='mydist')
b.get_value(qualifier='teff', component='primary', distribution='mydist')
_ = b.get_value(qualifier='teff', component='primary', distribution='mydist').plot(show=True)
Explanation: However, b.add_distribution will populate unit and wrap_at (when applicable):
End of explanation
_ = b.plot_distribution_collection(distribution='mydist')
Explanation: And whenever plotting through b.plot_distribution_collection or b.plot, the latex representation of the respective parameters will be included.
End of explanation
help(phoebe.gaussian)
help(phoebe.gaussian_around)
Explanation: "Around" distributions
If we look at the API docs for gaussian and gaussian_around, we'll notice that they're essentially the same, except that gaussian_around does not require the first loc argument.
End of explanation
b = phoebe.default_binary()
print(b.get_value(qualifier='teff', component='primary'))
b.add_distribution('teff@primary', phoebe.gaussian(6000, 100), distribution='gaussian_dist')
b.add_distribution('teff@primary', phoebe.gaussian_around(100), distribution='gaussian_around_dist')
Explanation: When attached in PHOEBE, any "around" distribution will have its central value updated to always be that of the current parameter value to which its attached.  This can be very convenient in some cases (for example, setting init_from to always be an N-dimensional Gaussian "ball" around the current values), but in other cases is not appropriate (for priors, where any attached distribution should be based on external knowledge or assumptions, and therefore should be fixed and not update with changing parameter values).
Now we'll attach both a gaussian and gaussian_around distribution and see how they behave differently.
End of explanation
print(b.filter(context='distribution'))
Explanation: Since the central value is currently 6000, these two distributions are currently identical (the value in the gaussian_around is the current value that will be adopted as loc whenever the distribution is actually used).
End of explanation
b.set_value('teff', component='primary', context='component', value=6123)
print(b.filter(context='distribution'))
Explanation: However, if we change the parameter value, we can see that the "around" distribution updates its central value accordingly.
End of explanation
help(phoebe.uniform)
help(phoebe.uniform_around)
Explanation: Note that if we try to use any distribution-set with an "around" distribution as priors in a solver, a warning will be raised (as of PHOEBE 2.3.23).
Similar to gaussian and gaussian_around, uniform takes a lower and upper bound, whereas uniform_around only takes a width, with the central value adopted from the current face-value.
End of explanation
help(phoebe.mvhistogram_from_data)
help(phoebe.mvgaussian)
Explanation: Multivariate distributions
Multivariate distributions allow for storing the covariance between the distributions of multiple parameters.  Although the creation functions are exposed at the top-level, these are most seen in PHOEBE after running an MCMC chain.  For more information on manipulating these multivariate posteriors, see Advanced: Convert Posterior Distributions from EMCEE.  
If, however, we had an MCMC chain or wanted to import a published covariance matrix, we could use mvhistogram_from_data or mvgaussian, respectively.
End of explanation
import numpy as np
b = phoebe.default_binary()
dist = phoebe.mvgaussian([6500, 6200, 0.9], 
                         np.array([[ 2,  1, -1],
                                   [ 1,  2,  1],
                                   [-1,  1,  2]]),
                        allow_singular=True,
                        labels=['T1', 'T2', 'q'])
_ = dist.plot(show=True)
Explanation: Once we create our single distl multivariate object, we then need to tell PHOEBE which "slices" of that multivariate distribution to attach to which parameters.
Here we will set labels, just to make it easier to track the dimensions of the distribution object.
End of explanation
_ = dist.slice('T1').plot()
dist.slice('T1')
b.add_distribution({'teff@primary': dist.slice('T1'),
                    'teff@secondary': dist.slice('T2'),
                     'q': dist.slice('q')},
                    distribution='mydist')
Explanation: By calling dist.slice, we get a distl object which retains the covariance matrix, but represents a single dimension, which can then be passed to PHOEBE.
End of explanation
_ = b.plot_distribution_collection('mydist', show=True)
Explanation: And we can see that the covariances (although stored three separate times) are maintained whenever sampling from the distributions within PHOEBE.
End of explanation
<END_TASK>