Skip to content

Commit

Permalink
xlims and ylims are determined automatically from the data (with defa…
Browse files Browse the repository at this point in the history
…ults)

yticks are spaced at intervals of 10^-50, no matter the size of the data
  • Loading branch information
caiw committed Nov 10, 2023
1 parent 0fffc0f commit 08bf297
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 23 deletions.
32 changes: 16 additions & 16 deletions demos/demo_plotting.ipynb

Large diffs are not rendered by default.

67 changes: 60 additions & 7 deletions kymata/plot/plotting.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from os import path
from pathlib import Path
from itertools import cycle
from typing import Optional, Sequence, Dict, Tuple
from typing import Optional, Sequence, Dict
from statistics import NormalDist

from matplotlib import pyplot, colors
Expand All @@ -20,6 +21,7 @@ def expression_plot(
# Style kwargs
color: Optional[str | Dict[str, str] | list[str]] = None, # colour name, function_name → colour name, or list of colour names
ylim: Optional[float] = None,
xlims: Optional[tuple[Optional[float], Optional[float]]] = None, # Whole thing None to use default values, either entry None to use default for that value
# I/O args
save_to: Optional[Path] = None,
):
Expand All @@ -40,8 +42,6 @@ def expression_plot(
# List specified, then pair up in order
assert len(color) == len(str)
color = {f: c for f, c in zip(show_only, color)}
if ylim is None:
ylim = 10 ** -150

# Default colours
cycol = cycle(color_palette("Set1"))
Expand All @@ -66,6 +66,10 @@ def expression_plot(

custom_handles = []
custom_labels = []
data_x_min, data_x_max = np.Inf, -np.Inf
# Careful, the y value is inverted, with y==1 on the origin and y<1 away from the origin.
# "y_min" here is real absolute min value in the data (closest to zero)
data_y_min = np.Inf
for function in show_only:

custom_handles.extend([Line2D([], [], marker='.', color=color[function], linestyle='None')])
Expand All @@ -87,20 +91,32 @@ def expression_plot(
right_hem_expression_plot.vlines(x=x_right, ymin=1, ymax=y_right, color=right_color)
right_hem_expression_plot.scatter(x_right, y_right, color=right_color, s=20)

data_x_min = min(data_x_min,
x_left.min() if len(x_left) > 0 else np.Inf,
x_right.min() if len(x_right) > 0 else np.Inf)
data_x_max = max(data_x_max,
x_left.max() if len(x_left) > 0 else -np.Inf,
x_right.max() if len(x_right) > 0 else- np.Inf)
data_y_min = min(data_y_min,
y_left.min() if len(y_left) > 0 else np.Inf,
y_right.min() if len(y_right) > 0 else np.Inf)

# format shared axis qualities

for plot in [right_hem_expression_plot, left_hem_expression_plot]:
plot.set_yscale('log')
# TODO: hard-coded?
plot.set_xlim(-200, 800)
xlims = _get_best_xlims(xlims, data_x_min, data_x_max)
ylim = _get_best_ylim(ylim, data_y_min)
plot.set_xlim(*xlims)
plot.set_ylim((1, ylim))
plot.axvline(x=0, color='k', linestyle='dotted')
plot.axhline(y=sidak_corrected_alpha, color='k', linestyle='dotted')
plot.text(-100, sidak_corrected_alpha, 'α*',
bbox={'facecolor': 'white', 'edgecolor': 'none'}, verticalalignment='center')
plot.text(600, sidak_corrected_alpha, 'α*',
bbox={'facecolor': 'white', 'edgecolor': 'none'}, verticalalignment='center')
plot.set_yticks(np.geomspace(start=1, stop=ylim, num=4))
plot.set_yticks(_get_yticks(ylim))

# format one-off axis qualities
left_hem_expression_plot.set_title('Function Expression')
Expand Down Expand Up @@ -128,5 +144,42 @@ def expression_plot(
pyplot.close()


def lognuniform(low=0, high=1, size=None, base=np.e):
return np.random.uniform(low, high, size) / 1000000000000
def _get_best_xlims(xlims, data_x_min, data_x_max):
default_xlims = (-200, 800)
if xlims is None:
xlims = (None, None)
xmin, xmax = xlims
if xmin is None:
xmin = min(default_xlims[0], data_x_min)
if xmax is None:
xmax = max(default_xlims[1], data_x_max)
xlims = (xmin, xmax)
return xlims


def _get_best_ylim(ylim: float | None, data_y_min):
default_y_min = 10 ** -50
if ylim is not None:
return ylim
ylim = min(default_y_min, data_y_min)
# Round to nearest order of magnitude
order_of_magnitude = np.floor(np.log10(ylim) / 50) * 50
ylim = 10 ** order_of_magnitude
return ylim


def _get_yticks(ylim_oom):
order_of_magnitude = int(np.floor(np.log10(ylim_oom) / 50)) * -1
return np.geomspace(start=1, stop=ylim_oom, num=order_of_magnitude + 1)


if __name__ == '__main__':

# set location of tutorial data
sample_data_dir = Path(Path(path.abspath("")).parent.parent, "data", "sample-data")

# create new expression set object and add to it
expression_data_kymata_mirror = ExpressionSet.load(
from_path_or_file=Path(sample_data_dir, "kymata_mirror_Q3_2023_expression_endtable.nkg"))

expression_plot(expression_data_kymata_mirror, save_to=Path("/Users/cai/Desktop/temp.png"))

0 comments on commit 08bf297

Please sign in to comment.