Coverage for pyrc \ tools \ plotting.py: 25%
59 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-13 16:59 +0200
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-13 16:59 +0200
1# -------------------------------------------------------------------------------
2# Copyright (C) 2026 Joel Kimmich, Tim Jourdan
3# ------------------------------------------------------------------------------
4# License
5# This file is part of PyRC, distributed under GPL-3.0-or-later.
6# ------------------------------------------------------------------------------
8from datetime import timedelta, datetime
10import matplotlib.dates as mdates
11from mpl_toolkits.mplot3d.proj3d import proj_transform
12from mpl_toolkits.mplot3d.axes3d import Axes3D
13import numpy as np
14from matplotlib.patches import FancyArrowPatch
17class Arrow3D(FancyArrowPatch):
18 def __init__(self, start, end, *args, **kwargs):
19 super().__init__((0, 0), (0, 0), *args, **kwargs)
20 self._start = tuple(start)
21 self._end = tuple(end)
23 def make_arrow(self):
24 x1, y1, z1 = self._start
25 x2, y2, z2 = self._end
27 xs, ys, zs = proj_transform((x1, x2), (y1, y2), (z1, z2), self.axes.M)
28 self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
29 return zs
31 def draw(self, renderer):
32 self.make_arrow()
33 super().draw(renderer)
35 def do_3d_projection(self, renderer=None):
36 zs = self.make_arrow()
37 return np.min(zs)
40def custom_numeric_ticks_formatter(x, pos):
41 """
42 Format numbers/ticks to match ISO 80000.
44 Parameters
45 ----------
46 x : float | int
47 The number to format.
48 pos
50 Returns
51 -------
52 str :
53 The formatted number with a short protected space as thousands separator and a "," as decimal.
54 """
55 if abs(x) >= 1000:
56 s = f"{x:,.0f}".replace(",", "\u202f").replace(".", ",")
57 return s
58 else:
59 return f"{x:g}".replace(".", ",")
62def format_date_x_axis(start_date: datetime, end_date: datetime, ax, return_version: bool = True) -> str | None:
63 """
64 Formats the ticks of an axis as date.
66 Depending on the date range it parses the time/date to days, weeks, months and years with matching minor ticks.
68 Parameters
69 ----------
70 start_date : datetime
71 The start date of the axis.
72 end_date : datetime
73 The end date of the axis.
74 ax : matplotlib.axis.Axis
75 The axis to format.
76 return_version : bool
77 Whether to return the version of the axis or not.
79 Returns
80 -------
81 str | None :
82 The formatted Axis if return_version is True, otherwise None.
83 """
84 time_delta = end_date - start_date
85 if time_delta <= timedelta(days=3):
86 version = "day"
87 ax.xaxis.set_major_locator(mdates.HourLocator(byhour=(0, 6, 12, 18)))
88 ax.xaxis.set_minor_locator(mdates.HourLocator())
89 ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m. %-H Uhr"))
90 elif time_delta <= timedelta(days=10):
91 version = "week"
92 ax.xaxis.set_major_locator(mdates.DayLocator())
93 ax.xaxis.set_minor_locator(mdates.HourLocator(byhour=(0, 6, 12, 18)))
94 ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m."))
95 elif time_delta <= timedelta(days=80):
96 version = "month"
97 ax.xaxis.set_major_locator(mdates.DayLocator(bymonthday=(1, 7, 15, 23)))
98 ax.xaxis.set_minor_locator(mdates.DayLocator())
99 ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m."))
100 else:
101 version = "year"
102 ax.xaxis.set_major_locator(mdates.MonthLocator())
103 ax.xaxis.set_minor_locator(mdates.DayLocator(bymonthday=(1, 7, 14, 21, 28)))
104 ax.xaxis.set_major_formatter(mdates.DateFormatter("%-m."))
105 ax.grid(True)
106 ax.tick_params(axis="x", which="minor", bottom=True)
107 ax.set_xlim(left=start_date)
108 ax.set_xlim(right=end_date)
109 if return_version:
110 return version
113def _arrow3D(ax, start, end, *args, **kwargs):
114 """Add an 3d arrow to an `Axes3D` instance."""
116 arrow = Arrow3D(start, end, *args, **kwargs)
117 ax.add_artist(arrow)
120setattr(Axes3D, "arrow3D", _arrow3D)
122# example usage
123# fig = plt.figure()
124# ax = fig.add_subplot(111, projection='3d')
125# ax.set_xlim(0,2)
126# ax.arrow3D((0,0,0),
127# (1,1,1),
128# mutation_scale=10,
129# arrowstyle="-|>",
130# linestyle="-")
131# ax.arrow3D((1,0,0),
132# (2,1,1),
133# mutation_scale=20,
134# ec ="green",
135# fc="red")
136# ax.set_title('3D Arrows Demo')
137# ax.set_xlabel('x')
138# ax.set_ylabel('y')
139# ax.set_zlabel('z')
140# fig.tight_layout()
141# plt.show()