Skip to content

Commit

Permalink
Started working on log axis ticks
Browse files Browse the repository at this point in the history
  • Loading branch information
slaclau committed Jul 17, 2024
1 parent bb39d23 commit 8a3da55
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 25 deletions.
4 changes: 2 additions & 2 deletions src/plotly_gtk/_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,9 @@ def _calc_pos(
)

if log_x and not ignore_log_x:
x = np.log(x)
x = np.log10(x)
if log_y and not ignore_log_y:
y = np.log(y)
y = np.log10(y)

x_pos = []
y_pos = []
Expand Down
6 changes: 3 additions & 3 deletions src/plotly_gtk/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def _update_ranges(self):
if "_range" not in self.layout[axis]:
continue
if self.layout[axis]["_type"] == "log":
self.layout[axis]["_range"] = np.log(self.layout[axis]["_range"])
self.layout[axis]["_range"] = np.log10(self.layout[axis]["_range"])
else:
range_length = (
self.layout[axis]["_range"][-1] - self.layout[axis]["_range"][0]
Expand Down Expand Up @@ -513,7 +513,7 @@ def _update_layout(self):
),
)
for xaxis in xaxes:
if "type" not in xaxis:
if "type" not in self.layout[xaxis]:
first_plot_on_axis = [
trace
for trace in self.data
Expand All @@ -527,7 +527,7 @@ def _update_layout(self):
template[xaxis] = template["xaxis"]
defaults[xaxis] = defaults["xaxis"]
for yaxis in yaxes:
if "type" not in yaxis:
if "type" not in self.layout[yaxis]:
first_plot_on_axis = [
trace
for trace in self.data
Expand Down
20 changes: 19 additions & 1 deletion src/plotly_gtk/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,27 @@
"line_2",
]
demos = {"Scatter": scatter_demos}
log_demos = ["log_1"]
demos = scatter_demos + log_demos


def get_test_figure(reference):
if reference in scatter_demos:
return _get_scatter_test_figure(reference)
if reference in log_demos:
return _get_log_test_figure(reference)


def _get_log_test_figure(reference):
if reference == "log_1":
df = px.data.gapminder().query("year == 2007")
fig = px.scatter(
df, x="gdpPercap", y="lifeExp", hover_name="country", log_x=True
)
return fig


def _get_scatter_test_figure(reference):
if reference == "scatter_1":
fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])
elif reference == "scatter_2":
Expand Down Expand Up @@ -61,7 +79,7 @@ def test(app):
paned = Gtk.Paned()
window.set_content(paned)

fig = get_test_figure("scatter_size_color_column")
fig = get_test_figure("log_1")
print(fig)
# print(fig["layout"]["template"])

Expand Down
97 changes: 78 additions & 19 deletions src/plotly_gtk/utils/ticks.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import math
import numbers

import numpy as np


Expand All @@ -16,15 +19,29 @@ def update_length(self, length):
self.length = length

def tick_first(self):
tmin = (
np.ceil(
(self.min - self.axis_layout["_tick0"]) / self.axis_layout["_dtick"]
axrev = self.axis_layout["_range"][-1] < self.axis_layout["_range"][0];
round_func = np.floor if axrev else np.ceil
if isinstance(self.axis_layout["_dtick"], numbers.Number):
tmin = (
round_func(
(self.min - self.axis_layout["_tick0"]) / self.axis_layout["_dtick"]
)
* self.axis_layout["_dtick"]
+ self.axis_layout["_tick0"]
)
* self.axis_layout["_dtick"]
+ self.axis_layout["_tick0"]
)
return tmin

return tmin
ttype = self.axis_layout["_dtick"][0]
dtnum = int(self.axis_layout["_dtick"][1:])
if ttype == "M":
# TODO: Implement M type ticks
raise NotImplementedError("M type ticks not implemented yet")
if ttype == "L":
return np.log10(round_func((np.power(10, self.axis_layout["_range"][0]) - self.axis_layout["_tick0"]) / dtnum) *dtnum + self.axis_layout["_tick0"])
if ttype == "D":
# TODO: Finish
tickset = self.ROUND_SET["LOG2"] if dtnum == 2 else self.ROUND_SET["LOG1"]
frac = self.round_up(self.axis_layout["_range"][0] % 1, tickset, axrev)
return np.floor(self.axis_layout["_range"][0])
def calculate(self):
self.min = self.axis_layout["_range"][0]
self.max = self.axis_layout["_range"][-1]
Expand All @@ -33,11 +50,21 @@ def calculate(self):
if "tickmode" in self.axis_layout and self.axis_layout["tickmode"] == "array":
return self.array_ticks()

self.axis_layout["_tickvals"] = np.arange(
self.tick_first(),
self.max,
self.axis_layout["_dtick"],
)
if self.axis_layout["_type"] == "log":
self.axis_layout["_tickvals"] = np.power(
10,
np.arange(
self.tick_first(),
self.max,
self.axis_layout["_dtick"],
),
)
else:
self.axis_layout["_tickvals"] = np.arange(
self.tick_first(),
self.max,
self.axis_layout["_dtick"],
)
self.axis_layout["_ticktext"] = np.char.mod("%g", self.axis_layout["_tickvals"])
return self.axis_layout["_tickvals"]

Expand All @@ -54,7 +81,8 @@ def prepare(self):
self.auto_ticks((self.max - self.min) / nt)

@staticmethod
def round_up(value, rounding_set):
def round_up(value, rounding_set, rev=False):
# TODO: rev
if value <= np.max(rounding_set):
return rounding_set[np.argwhere(np.array(rounding_set) > value)[0][0]]
return max(rounding_set)
Expand All @@ -68,11 +96,42 @@ def auto_ticks(self, rough_dtick):
def get_base(v):
return np.power(v, np.floor(np.log(rough_dtick) / np.log(10)))

self.axis_layout["_tick0"] = 0
base = get_base(10)
self.axis_layout["_dtick"] = self.round_dtick(
rough_dtick, base, self.ROUND_SET[10]
)
if self.axis_layout["_type"] == "log":
print(rough_dtick)
self.axis_layout["_tick0"] = 0
if rough_dtick > 0.7:
self.axis_layout["_dtick"] = np.ceil(rough_dtick)
elif (
np.abs(self.axis_layout["_range"][-1] - self.axis_layout["_range"][0])
< 1
):
nt = (
1.5
* np.abs(
self.axis_layout["_range"][-1] - self.axis_layout["_range"][0]
)
/ rough_dtick
)
rough_dtick = (
np.abs(
np.power(10, self.axis_layout["_range"][-1])
- np.power(10, self.axis_layout["_range"][0])
)
/ nt
)
base = get_base(10)
self.axis_layout["_dtick"] = "L" + str(
self.round_dtick(rough_dtick, base, self.ROUND_SET[10])
)
else:
self.axis_layout["_dtick"] = "D2" if rough_dtick > 0.3 else "D1"
print(self.axis_layout)
else:
self.axis_layout["_tick0"] = 0
base = get_base(10)
self.axis_layout["_dtick"] = self.round_dtick(
rough_dtick, base, self.ROUND_SET[10]
)

def array_ticks(self):
vals = self.axis_layout["tickvals"]
Expand Down

0 comments on commit 8a3da55

Please sign in to comment.