quicklooks 0.0.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quicklooks-0.0.11/LICENSE +21 -0
- quicklooks-0.0.11/MANIFEST.in +1 -0
- quicklooks-0.0.11/PKG-INFO +44 -0
- quicklooks-0.0.11/README.md +21 -0
- quicklooks-0.0.11/quicklooks/__init__.py +28 -0
- quicklooks-0.0.11/quicklooks/bar_plot.py +127 -0
- quicklooks-0.0.11/quicklooks/chart_skeleton.py +260 -0
- quicklooks-0.0.11/quicklooks/cs_attributes.py +115 -0
- quicklooks-0.0.11/quicklooks/dist_plot.py +140 -0
- quicklooks-0.0.11/quicklooks/fonts/lato/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/lato/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/montserrat/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/montserrat/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/oswald/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/oswald/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/roboto/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/roboto/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/rubik/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/rubik/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/source_sans/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/source_sans/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/work_sans/text.ttf +0 -0
- quicklooks-0.0.11/quicklooks/fonts/work_sans/title.ttf +0 -0
- quicklooks-0.0.11/quicklooks/legend.py +49 -0
- quicklooks-0.0.11/quicklooks/line_plot.py +144 -0
- quicklooks-0.0.11/quicklooks/plot_and_text_styling.py +214 -0
- quicklooks-0.0.11/quicklooks/reference_line.py +91 -0
- quicklooks-0.0.11/quicklooks/save_chart.py +19 -0
- quicklooks-0.0.11/quicklooks/scatter_plot.py +108 -0
- quicklooks-0.0.11/quicklooks/templates.py +39 -0
- quicklooks-0.0.11/quicklooks/text.py +64 -0
- quicklooks-0.0.11/quicklooks.egg-info/PKG-INFO +44 -0
- quicklooks-0.0.11/quicklooks.egg-info/SOURCES.txt +36 -0
- quicklooks-0.0.11/quicklooks.egg-info/dependency_links.txt +1 -0
- quicklooks-0.0.11/quicklooks.egg-info/requires.txt +5 -0
- quicklooks-0.0.11/quicklooks.egg-info/top_level.txt +1 -0
- quicklooks-0.0.11/setup.cfg +4 -0
- quicklooks-0.0.11/setup.py +35 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Alex Breslav
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include quicklooks/fonts *
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: quicklooks
|
|
3
|
+
Version: 0.0.11
|
|
4
|
+
Summary: quicklook is a Python package for visualizing data quickly using matplotlib.
|
|
5
|
+
Home-page: https://www.linkedin.com/in/alexanderbreslav/
|
|
6
|
+
Author: Alex Breslav
|
|
7
|
+
Author-email: alexdsbreslav@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: matplotlib,data-visualization,python
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
Requires-Dist: matplotlib
|
|
20
|
+
Requires-Dist: pandas
|
|
21
|
+
Requires-Dist: datetime
|
|
22
|
+
Requires-Dist: seaborn
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
# quicklooks
|
|
27
|
+
quicklook is a Python package for visualizing data quickly.
|
|
28
|
+
Check out the documentation by clicking [here](https://github.com/alexdsbreslav/quicklook/tree/master/how_to_use_quicklook) or by navigating to the folder `how_to_use_quicklook`.
|
|
29
|
+
|
|
30
|
+
## Why quicklooks?
|
|
31
|
+
Creating attractive, ready-to-share data visualizations takes forever. quickook is a cut-and-paste Python package that does the design work for you and makes it easy to create beautifuly simple data visualizations.
|
|
32
|
+
|
|
33
|
+
## Who is quicklooks best for?
|
|
34
|
+
quicklook is for any data scientist, product manager, or researcher that knows a little bit of Python and is analyzing their data in a Jupyter Notebook. My goal in writing quicklook was to make data viz more efficient, but in the process, I've also created a package that is easy to use for beginners.
|
|
35
|
+
|
|
36
|
+
## To install...
|
|
37
|
+
Directions to come; I am currently overhauling the package and will upload to pip for easy installation.
|
|
38
|
+
|
|
39
|
+
## Documentation
|
|
40
|
+
The [documentation is here](https://github.com/alexdsbreslav/quicklook/tree/master/how_to_use_quicklook).
|
|
41
|
+
|
|
42
|
+
## Acknowledgments
|
|
43
|
+
quicklook is built using [Matplotlib](https://matplotlib.org/), [NumPy](https://numpy.org/), [Pandas](https://pandas.pydata.org/), [Coolors](https://coolors.co/), and [seaborn](https://seaborn.pydata.org/).
|
|
44
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# quicklooks
|
|
4
|
+
quicklook is a Python package for visualizing data quickly.
|
|
5
|
+
Check out the documentation by clicking [here](https://github.com/alexdsbreslav/quicklook/tree/master/how_to_use_quicklook) or by navigating to the folder `how_to_use_quicklook`.
|
|
6
|
+
|
|
7
|
+
## Why quicklooks?
|
|
8
|
+
Creating attractive, ready-to-share data visualizations takes forever. quickook is a cut-and-paste Python package that does the design work for you and makes it easy to create beautifuly simple data visualizations.
|
|
9
|
+
|
|
10
|
+
## Who is quicklooks best for?
|
|
11
|
+
quicklook is for any data scientist, product manager, or researcher that knows a little bit of Python and is analyzing their data in a Jupyter Notebook. My goal in writing quicklook was to make data viz more efficient, but in the process, I've also created a package that is easy to use for beginners.
|
|
12
|
+
|
|
13
|
+
## To install...
|
|
14
|
+
Directions to come; I am currently overhauling the package and will upload to pip for easy installation.
|
|
15
|
+
|
|
16
|
+
## Documentation
|
|
17
|
+
The [documentation is here](https://github.com/alexdsbreslav/quicklook/tree/master/how_to_use_quicklook).
|
|
18
|
+
|
|
19
|
+
## Acknowledgments
|
|
20
|
+
quicklook is built using [Matplotlib](https://matplotlib.org/), [NumPy](https://numpy.org/), [Pandas](https://pandas.pydata.org/), [Coolors](https://coolors.co/), and [seaborn](https://seaborn.pydata.org/).
|
|
21
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'''
|
|
2
|
+
PLACEHOLDER FOR INSTRUCTIONS
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
# ---- chart skeleton
|
|
6
|
+
from .chart_skeleton import chart_skeleton
|
|
7
|
+
from .cs_attributes import chart_size
|
|
8
|
+
from .cs_attributes import chart_xlabel
|
|
9
|
+
from .cs_attributes import chart_ylabel
|
|
10
|
+
from .cs_attributes import color_libraries
|
|
11
|
+
from .cs_attributes import fonts
|
|
12
|
+
|
|
13
|
+
# ---- plots
|
|
14
|
+
from .bar_plot import bar_plot
|
|
15
|
+
from .line_plot import line_plot
|
|
16
|
+
from .dist_plot import distribution_plot
|
|
17
|
+
from .scatter_plot import scatter_plot
|
|
18
|
+
|
|
19
|
+
# ---- reference items
|
|
20
|
+
from .reference_line import reference_line
|
|
21
|
+
from .legend import legend
|
|
22
|
+
from .text import text
|
|
23
|
+
|
|
24
|
+
# ---- templates
|
|
25
|
+
from .templates import templates
|
|
26
|
+
|
|
27
|
+
# ---- save function
|
|
28
|
+
from .save_chart import save_chart
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
|
|
4
|
+
class bar_plot:
|
|
5
|
+
"""
|
|
6
|
+
bar = ql.bar_plot(chart_skeleton,
|
|
7
|
+
xlabels = ,
|
|
8
|
+
y = ,
|
|
9
|
+
yerror = None, #If no values, None
|
|
10
|
+
bars_per_xlabel = 1,
|
|
11
|
+
bar_index = 0,
|
|
12
|
+
color = chart_skeleton.color_library.default,
|
|
13
|
+
opacity = 1,
|
|
14
|
+
label = '',
|
|
15
|
+
layer_order = 1)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, chart_skeleton, xlabels, y, yerror, bars_per_xlabel,
|
|
19
|
+
bar_index, color, opacity, label, layer_order):
|
|
20
|
+
|
|
21
|
+
if not chart_skeleton.ax:
|
|
22
|
+
raise Exception('''The chart skeleton has not been built.
|
|
23
|
+
You must build a chart skeleton for each new plot that you want \
|
|
24
|
+
to create.''')
|
|
25
|
+
|
|
26
|
+
if chart_skeleton.xaxis_type == 'timeseries':
|
|
27
|
+
raise Exception('''The chart skeleton xtick_label is set to a
|
|
28
|
+
timeseries (e.g., months, days). This is not
|
|
29
|
+
compatible with a scatter plot.''')
|
|
30
|
+
|
|
31
|
+
if type(xlabels) in [str, int, float, bool]:
|
|
32
|
+
raise TypeError('''x is not properly defined.
|
|
33
|
+
x should be a 1 dimensional array of values.''')
|
|
34
|
+
|
|
35
|
+
if type(y) in [str, int, float, bool]:
|
|
36
|
+
raise TypeError('''y is not properly defined.
|
|
37
|
+
y should be a 1 dimensional array of values.''')
|
|
38
|
+
|
|
39
|
+
if type(yerror) in [str, int, float, bool]:
|
|
40
|
+
raise TypeError('''yerror is not properly defined. If you do not
|
|
41
|
+
need error represented on your line plot, set yerror = None.\n'
|
|
42
|
+
'If you need yerror on your line plot,
|
|
43
|
+
ensure that it is a 1 dimensional array of values.''')
|
|
44
|
+
|
|
45
|
+
if type(bar_index) is not int:
|
|
46
|
+
raise TypeError('''bar_index is not properly defined.
|
|
47
|
+
It must be an integer between 0 and bars_per_xlabel''')
|
|
48
|
+
|
|
49
|
+
if type(bars_per_xlabel) is not int or bars_per_xlabel < 1:
|
|
50
|
+
raise TypeError('''bars_per_xlabel is not properly defined.
|
|
51
|
+
It must be an integer >= 1''')
|
|
52
|
+
|
|
53
|
+
if bar_index >= bars_per_xlabel:
|
|
54
|
+
raise IndexError('''bar_index is not properly defined.
|
|
55
|
+
It must be an integer between 0 and bars_per_xlabel-1''')
|
|
56
|
+
|
|
57
|
+
# ---- check data shapes
|
|
58
|
+
if np.shape(np.shape(xlabels))[0] != 1:
|
|
59
|
+
raise ValueError('''x is not properly defined.; it is a {} x {} array.
|
|
60
|
+
x must be 1-dimensional array.'''.format(np.shape(xlabels)[0],
|
|
61
|
+
np.shape(xlabels)[1]))
|
|
62
|
+
if np.shape(np.shape(y))[0] != 1:
|
|
63
|
+
raise ValueError('''y is not properly defined.; it is a {} x {} array.
|
|
64
|
+
y must be 1-dimensional array.'''.format(np.shape(y)[0],
|
|
65
|
+
np.shape(y)[1]))
|
|
66
|
+
if np.shape(xlabels) != np.shape(y):
|
|
67
|
+
raise ValueError('''x and y are not the same shape. x has {} values
|
|
68
|
+
and y has {} values'''.format(np.shape(xlabels)[0], np.shape(y)[0]))
|
|
69
|
+
|
|
70
|
+
xlim = (-0.5,len(xlabels)-0.5)
|
|
71
|
+
plt.xlim(xlim[0], xlim[1]);
|
|
72
|
+
plt.xticks(ticks=range(len(xlabels)), labels=xlabels);
|
|
73
|
+
label_to_x = dict(zip(xlabels, chart_skeleton.ax.get_xticks()))
|
|
74
|
+
|
|
75
|
+
# ---- adjust for number of xlabels
|
|
76
|
+
width = 0.8 if len(xlabels) <= 2 else 0.8-(len(xlabels)*0.01)
|
|
77
|
+
# ---- adjust for number of bars at xlabel
|
|
78
|
+
width = width/bars_per_xlabel
|
|
79
|
+
|
|
80
|
+
# --- get offsets based on number of bars at xlabel
|
|
81
|
+
idx = [i for i in range(bars_per_xlabel)]
|
|
82
|
+
bar_offsets = [(i - np.median(idx))*1.1 for i in idx]
|
|
83
|
+
offset = bar_offsets[bar_index]*width
|
|
84
|
+
|
|
85
|
+
# ---- get x and y locs
|
|
86
|
+
ylim = chart_skeleton.ax.get_ylim()
|
|
87
|
+
x_loc = [label_to_x[i]+offset for i in xlabels]
|
|
88
|
+
bottom = np.array([(i/abs(i)) * ((ylim[1]-ylim[0])*0.002) for i in y])
|
|
89
|
+
height = y-bottom
|
|
90
|
+
zorder = 1
|
|
91
|
+
|
|
92
|
+
line = color[0]
|
|
93
|
+
fill = color[1]
|
|
94
|
+
edge = color[2]
|
|
95
|
+
|
|
96
|
+
bar = chart_skeleton.ax.bar(x=x_loc, width=width,
|
|
97
|
+
height=height, bottom=bottom,
|
|
98
|
+
color=fill,
|
|
99
|
+
edgecolor=edge,
|
|
100
|
+
linewidth=2,
|
|
101
|
+
joinstyle='round',
|
|
102
|
+
alpha=opacity,
|
|
103
|
+
label=label,
|
|
104
|
+
zorder = layer_order + 2)
|
|
105
|
+
|
|
106
|
+
if yerror is not None:
|
|
107
|
+
total_bars = bars_per_xlabel * len(x_loc)
|
|
108
|
+
if total_bars >= 30:
|
|
109
|
+
err_width = 2
|
|
110
|
+
elif total_bars >= 20:
|
|
111
|
+
err_width = 3
|
|
112
|
+
elif total_bars >= 10:
|
|
113
|
+
err_width = 4
|
|
114
|
+
else:
|
|
115
|
+
err_width = 5
|
|
116
|
+
|
|
117
|
+
for i in range(len(x_loc)):
|
|
118
|
+
chart_skeleton.ax.plot(np.full(10,x_loc[i]),
|
|
119
|
+
np.linspace(y[i]-yerror[i], y[i]+yerror[i],10),
|
|
120
|
+
linewidth=err_width, color=edge, alpha=opacity,
|
|
121
|
+
zorder = layer_order + 2+0.1, solid_capstyle='round');
|
|
122
|
+
else:
|
|
123
|
+
error = None
|
|
124
|
+
|
|
125
|
+
self.bar_obj = bar
|
|
126
|
+
self.xlim = xlim
|
|
127
|
+
self.zorder = layer_order + 2
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
from .plot_and_text_styling import *
|
|
3
|
+
from .cs_attributes import *
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from dateutil import relativedelta
|
|
6
|
+
import matplotlib.dates as mdates
|
|
7
|
+
|
|
8
|
+
class chart_skeleton:
|
|
9
|
+
"""
|
|
10
|
+
chart_skeleton = ql.chart_skeleton(
|
|
11
|
+
size = ql.chart_size.notebook,
|
|
12
|
+
color_library = ql.color_libraries.skygrove,
|
|
13
|
+
font = ql.fonts.rubik,
|
|
14
|
+
title = '',
|
|
15
|
+
xlabel = '',
|
|
16
|
+
ylabel = '',
|
|
17
|
+
x_min_max = (0,1), y_min_max = (0,1),
|
|
18
|
+
xtick_interval = 0.25, ytick_interval = 0.25,
|
|
19
|
+
xtick_labels = ql.chart_xlabel.default,
|
|
20
|
+
ytick_labels = ql.chart_ylabel.default,
|
|
21
|
+
horizontal_gridlines_on = False,
|
|
22
|
+
vertical_gridlines_on = False);
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, size, color_library, font, title, ylabel, xlabel, x_min_max,
|
|
26
|
+
y_min_max, xtick_interval, ytick_interval, xtick_labels,
|
|
27
|
+
ytick_labels, horizontal_gridlines_on, vertical_gridlines_on):
|
|
28
|
+
|
|
29
|
+
# ---- size
|
|
30
|
+
# ---- affects markersize for line and scatter plots
|
|
31
|
+
self.size = size
|
|
32
|
+
|
|
33
|
+
# ---- colors
|
|
34
|
+
self.color_library = color_library
|
|
35
|
+
|
|
36
|
+
# ---- font
|
|
37
|
+
self.font = font
|
|
38
|
+
|
|
39
|
+
# ---- title
|
|
40
|
+
if type(title) is not str:
|
|
41
|
+
raise AttributeError('title not properly define: must be a string \
|
|
42
|
+
(e.g., Daily Active Users)')
|
|
43
|
+
|
|
44
|
+
# ---- ylabel
|
|
45
|
+
if type(ylabel) is not str:
|
|
46
|
+
raise AttributeError('ylabel not properly define: must be a string \
|
|
47
|
+
(e.g., "Daily Active Users")')
|
|
48
|
+
|
|
49
|
+
# ---- xlabel
|
|
50
|
+
if type(xlabel) is not str:
|
|
51
|
+
raise AttributeError('xlabel not properly define: must be a string \
|
|
52
|
+
(e.g., "Date")')
|
|
53
|
+
|
|
54
|
+
# ---- y_min_max
|
|
55
|
+
# ---- req for reference_line
|
|
56
|
+
if type(y_min_max) is tuple and y_min_max[1] > y_min_max[0]:
|
|
57
|
+
self.y_min_max = y_min_max
|
|
58
|
+
yrange = y_min_max[1] - y_min_max[0]
|
|
59
|
+
self.yrange = yrange
|
|
60
|
+
|
|
61
|
+
else:
|
|
62
|
+
raise AttributeError('y_min_max must be a tuple (e.g., (0,1) where\
|
|
63
|
+
the second value is greater than the first')
|
|
64
|
+
|
|
65
|
+
# ---- xtick_labels
|
|
66
|
+
if type(xtick_labels) not in [str, list]:
|
|
67
|
+
raise Exception('xtick_labels not properly defined: xtick_labels \
|
|
68
|
+
must be set to default, percents, or defined \
|
|
69
|
+
as a list of strings.')
|
|
70
|
+
|
|
71
|
+
# ---- set xaxis_type (will overwrite if timeseries)
|
|
72
|
+
xaxis_type = 'default'
|
|
73
|
+
|
|
74
|
+
# ---- check that label type and min_max match
|
|
75
|
+
if xtick_labels in ['years', 'months', 'quarters', 'days']:
|
|
76
|
+
if type(x_min_max[0]) is not str or type(x_min_max[1]) is not str:
|
|
77
|
+
raise TypeError('''If xtick label is set to a timeseries,
|
|
78
|
+
x_min_max must be a tuple with two date strings in the format
|
|
79
|
+
YYYY-MM-DD''')
|
|
80
|
+
# ---- if they do, convert str to datetime
|
|
81
|
+
else:
|
|
82
|
+
x_min_max = (datetime.strptime(x_min_max[0], '%Y-%m-%d'),
|
|
83
|
+
datetime.strptime(x_min_max[1], '%Y-%m-%d'))
|
|
84
|
+
|
|
85
|
+
xaxis_type = 'timeseries'
|
|
86
|
+
|
|
87
|
+
# ---- req for reference line
|
|
88
|
+
self.xaxis_type = xaxis_type
|
|
89
|
+
|
|
90
|
+
# ---- ytick_labels
|
|
91
|
+
if type(ytick_labels) not in [str, list]:
|
|
92
|
+
raise Exception('''ytick_labels not properly defined: ytick_labels
|
|
93
|
+
must be set to default, percents, or defined as a
|
|
94
|
+
list of strings.''')
|
|
95
|
+
|
|
96
|
+
# ---- check xtick labels
|
|
97
|
+
# ---- for timeseries
|
|
98
|
+
def_error = False
|
|
99
|
+
int_error = False
|
|
100
|
+
|
|
101
|
+
if xaxis_type == 'timeseries':
|
|
102
|
+
xrange = (x_min_max[1] - x_min_max[0]).days
|
|
103
|
+
rd = relativedelta.relativedelta(x_min_max[1], x_min_max[0])
|
|
104
|
+
|
|
105
|
+
if xtick_labels == 'days':
|
|
106
|
+
def_error = True if xtick_interval > xrange else False
|
|
107
|
+
int_error = True if 20*xtick_interval < xrange else False
|
|
108
|
+
|
|
109
|
+
elif xtick_labels == 'months':
|
|
110
|
+
if 2 > rd.years * 12 + rd.months:
|
|
111
|
+
raise Exception('''xtick_interval not properly defined.
|
|
112
|
+
Use days if the date range <= 3 months''')
|
|
113
|
+
elif 15 < rd.years * 12 + rd.months:
|
|
114
|
+
raise Exception('''xtick_interval not properly defined.
|
|
115
|
+
Use quarters if the date range > 15 months''')
|
|
116
|
+
|
|
117
|
+
elif xtick_labels == 'quarters':
|
|
118
|
+
if 9 > rd.years * 12 + rd.months:
|
|
119
|
+
raise Exception('''xtick_interval not properly defined.
|
|
120
|
+
Use months if the date range <= 9 months''')
|
|
121
|
+
elif 48 < rd.years * 12 + rd.months:
|
|
122
|
+
raise Exception('''xtick_interval not properly defined.
|
|
123
|
+
Use quarters if the date range > 16 quarters''')
|
|
124
|
+
|
|
125
|
+
elif xtick_labels == 'years':
|
|
126
|
+
def_error = True if xtick_interval > rd.years else False
|
|
127
|
+
int_error = True if 20*xtick_interval < rd.years else False
|
|
128
|
+
|
|
129
|
+
# ---- for everything else
|
|
130
|
+
else:
|
|
131
|
+
xrange = x_min_max[1] - x_min_max[0]
|
|
132
|
+
def_error = True if xtick_interval > xrange else False
|
|
133
|
+
int_error = True if 20*xtick_interval < xrange else False
|
|
134
|
+
|
|
135
|
+
if def_error:
|
|
136
|
+
raise Exception('''xtick_interval not properly defined.
|
|
137
|
+
Decrease the xtick_interval or change the xtick_labels''')
|
|
138
|
+
if int_error:
|
|
139
|
+
raise Exception('''xtick_interval is too small.
|
|
140
|
+
Increase the xtick_interval or change the xtick_labels''')
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
self.x_min_max = x_min_max
|
|
144
|
+
# ---- req for reference line
|
|
145
|
+
self.xrange = xrange
|
|
146
|
+
|
|
147
|
+
# ---- check ytick_labels
|
|
148
|
+
if ytick_interval > yrange:
|
|
149
|
+
raise Exception('''ytick_interval not properly defined;
|
|
150
|
+
decrease the ytick_interval''')
|
|
151
|
+
|
|
152
|
+
elif 20*ytick_interval < yrange:
|
|
153
|
+
raise Exception('''ytick_interval is too small;
|
|
154
|
+
increase the ytick_interval.''')
|
|
155
|
+
|
|
156
|
+
# ---- vertical gridlines
|
|
157
|
+
if type(vertical_gridlines_on) is not bool:
|
|
158
|
+
raise AttributeError('Vertical gridlines is not properly defined: \
|
|
159
|
+
vertical_gridlines_on must be set to \
|
|
160
|
+
True or False.')
|
|
161
|
+
|
|
162
|
+
# ---- horizontal gridlines
|
|
163
|
+
if type(horizontal_gridlines_on) is not bool:
|
|
164
|
+
raise AttributeError('Horizontal gridlines is not properly defined: \
|
|
165
|
+
horizontal_gridlines_on must be set to \
|
|
166
|
+
True or False.')
|
|
167
|
+
|
|
168
|
+
# ----------------------------------------------------------------------
|
|
169
|
+
# style the plot -------------------------------------------------------
|
|
170
|
+
# ----------------------------------------------------------------------
|
|
171
|
+
# ---- define plot style based on style and size choice
|
|
172
|
+
ps = chart_skeleton_style(size, ylabel)
|
|
173
|
+
fs = font_style(size, self)
|
|
174
|
+
|
|
175
|
+
# ---- req for legend and text
|
|
176
|
+
self.plot_style = ps
|
|
177
|
+
self.font_style = fs
|
|
178
|
+
|
|
179
|
+
# ---- create the plot
|
|
180
|
+
fig, ax = plt.subplots(nrows=1, figsize = ps.figsize)
|
|
181
|
+
self.ax = ax
|
|
182
|
+
|
|
183
|
+
# ---- add the title
|
|
184
|
+
ax.set_title(title, color = color_library.text,
|
|
185
|
+
pad = ps.title_pad, fontproperties = fs.title)
|
|
186
|
+
|
|
187
|
+
# ---- create a patch to set the background color of the plot
|
|
188
|
+
ax.patch.set_xy((-0.16, -0.14))
|
|
189
|
+
ax.patch.set_height(1.2)
|
|
190
|
+
ax.patch.set_width(1.28)
|
|
191
|
+
ax.set_facecolor(color_library.background)
|
|
192
|
+
|
|
193
|
+
# ---- set facecolor of fig (around ax face)
|
|
194
|
+
fig.set_facecolor(color_library.background)
|
|
195
|
+
|
|
196
|
+
# ---- add grid lines if necessary
|
|
197
|
+
if horizontal_gridlines_on == True:
|
|
198
|
+
ax.yaxis.grid(which='major', linestyle=':',
|
|
199
|
+
linewidth = ps.linewidth, color = '0.8', zorder=1)
|
|
200
|
+
|
|
201
|
+
if vertical_gridlines_on == True:
|
|
202
|
+
ax.xaxis.grid(which='major', linestyle=':',
|
|
203
|
+
linewidth = ps.linewidth, color = '0.8', zorder=1)
|
|
204
|
+
|
|
205
|
+
# ---- style the axis lines
|
|
206
|
+
for spine in ['top', 'right']:
|
|
207
|
+
ax.spines[spine].set_visible(False)
|
|
208
|
+
for spine in ['bottom', 'left']:
|
|
209
|
+
ax.spines[spine].set_linewidth(ps.linewidth)
|
|
210
|
+
ax.spines[spine].set_color(color_library.text)
|
|
211
|
+
ax.spines[spine].set_zorder(2)
|
|
212
|
+
|
|
213
|
+
# ---- style the axis ticks
|
|
214
|
+
for i in range(2):
|
|
215
|
+
ax.tick_params(['x','y'][i],
|
|
216
|
+
colors=color_library.text,
|
|
217
|
+
width = ps.linewidth, pad = ps.tick_pad[i],
|
|
218
|
+
length = ps.tick_length)
|
|
219
|
+
|
|
220
|
+
for tick in ax.get_xticklabels():
|
|
221
|
+
tick.set_font_properties(fs.label)
|
|
222
|
+
for tick in ax.get_yticklabels():
|
|
223
|
+
tick.set_font_properties(fs.label)
|
|
224
|
+
|
|
225
|
+
# ---- set the axis limits and number of ticks
|
|
226
|
+
ax.set_ylim(y_min_max)
|
|
227
|
+
ax.set_xlim(x_min_max)
|
|
228
|
+
|
|
229
|
+
# ---- set the number of ticks on the axes
|
|
230
|
+
ax.yaxis.set_major_locator(plt.MultipleLocator(ytick_interval))
|
|
231
|
+
if xaxis_type == 'default':
|
|
232
|
+
ax.xaxis.set_major_locator(plt.MultipleLocator(xtick_interval))
|
|
233
|
+
else:
|
|
234
|
+
if xtick_labels == 'years':
|
|
235
|
+
ax.xaxis.set_major_locator(mdates.YearLocator(base=1))
|
|
236
|
+
print('xtick_interval ignored when xtick_label = years\n')
|
|
237
|
+
elif xtick_labels == 'quarters':
|
|
238
|
+
ax.xaxis.set_major_locator(mdates.MonthLocator((1,4,7,10)))
|
|
239
|
+
print('xtick_interval ignored when xtick_label = quarters\n')
|
|
240
|
+
elif xtick_labels == 'months':
|
|
241
|
+
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
|
|
242
|
+
print('xtick_interval ignored when xtick_label = months\n')
|
|
243
|
+
elif xtick_labels == 'days':
|
|
244
|
+
ax.xaxis.set_major_locator(mdates.DayLocator(interval=xtick_interval))
|
|
245
|
+
|
|
246
|
+
# ---- label the y axis
|
|
247
|
+
ax.set_ylabel(ylabel, color=color_library.text,
|
|
248
|
+
rotation = 90 if size == 'half_slide' else 0, labelpad = ps.label_pad[1],
|
|
249
|
+
horizontalalignment = 'center',
|
|
250
|
+
linespacing = 1.6, fontproperties = fs.label)
|
|
251
|
+
|
|
252
|
+
# ---- label the x axis
|
|
253
|
+
ax.set_xlabel(xlabel, color = color_library.text,
|
|
254
|
+
labelpad = ps.label_pad[0], fontproperties = fs.label)
|
|
255
|
+
|
|
256
|
+
# ---- set the x and y tick labels
|
|
257
|
+
set_tick_labels(xtick_labels, 'x', ax, x_min_max)
|
|
258
|
+
set_tick_labels(ytick_labels, 'y', ax, y_min_max)
|
|
259
|
+
|
|
260
|
+
plt.tight_layout()
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
class chart_ylabel:
|
|
2
|
+
default = 'default'
|
|
3
|
+
percents = 'percents'
|
|
4
|
+
millions = '1m'
|
|
5
|
+
hundredK = '100k'
|
|
6
|
+
thousands = '1k'
|
|
7
|
+
|
|
8
|
+
class chart_xlabel:
|
|
9
|
+
default = 'default'
|
|
10
|
+
percents = 'percents'
|
|
11
|
+
years = 'years'
|
|
12
|
+
quarters = 'quarters'
|
|
13
|
+
months = 'months'
|
|
14
|
+
days = 'days'
|
|
15
|
+
|
|
16
|
+
class chart_size:
|
|
17
|
+
notebook = 'notebook'
|
|
18
|
+
half_slide = 'half_slide'
|
|
19
|
+
full_slide = 'full_slide'
|
|
20
|
+
|
|
21
|
+
class fonts:
|
|
22
|
+
lato = 'lato'
|
|
23
|
+
montserrat = 'montserrat'
|
|
24
|
+
oswald = 'oswald'
|
|
25
|
+
roboto = 'roboto'
|
|
26
|
+
rubik = 'rubik'
|
|
27
|
+
source_sans = 'source_sans'
|
|
28
|
+
work_sans = 'work_sans'
|
|
29
|
+
|
|
30
|
+
class color_libraries:
|
|
31
|
+
class mariglow:
|
|
32
|
+
default = ['#9AA7FE', '#4B64FE', '#203DFE'] #blue
|
|
33
|
+
background = '#ffffff'
|
|
34
|
+
text = '#000000'
|
|
35
|
+
color_list = ['orange', 'peach', 'navy', 'blue']
|
|
36
|
+
orange = ['#EF7B57', '#E94819', '#BB3911']
|
|
37
|
+
peach = ['#FAF3EF', '#ECCFC0', '#DEAB91']
|
|
38
|
+
navy = ['#2C4177', '#1A2747', '#0B101E']
|
|
39
|
+
blue = ['#9AA7FE', '#4B64FE', '#203DFE']
|
|
40
|
+
light_gray = ['#f1f3f5', '#e9ecef', '#dee2e6']
|
|
41
|
+
gray = ['#ced4da', '#adb5bd', '#868e96']
|
|
42
|
+
dark_gray = ['#495057', '#343a40', '#212529']
|
|
43
|
+
black = ['#000000', '#000000', '#000000']
|
|
44
|
+
|
|
45
|
+
class skygrove:
|
|
46
|
+
default = ['#6E80D8', '#3E56CC', '#2B3FA1'] #blue
|
|
47
|
+
background = '#ffffff'
|
|
48
|
+
text = '#000000'
|
|
49
|
+
color_list = ['blue', 'periwinkle', 'sea_green', 'green_tea']
|
|
50
|
+
blue = ['#6E80D8', '#3E56CC', '#2B3FA1']
|
|
51
|
+
periwinkle = ['#EBEFFF', '#ADBEFF', '#708DFF']
|
|
52
|
+
sea_green = ['#57B27C', '#3E885B', '#2D6242']
|
|
53
|
+
green_tea = ['#EAF0D1', '#D5E1A3', '#BFD274']
|
|
54
|
+
light_gray = ['#f1f3f5', '#e9ecef', '#dee2e6']
|
|
55
|
+
gray = ['#ced4da', '#adb5bd', '#868e96']
|
|
56
|
+
dark_gray = ['#495057', '#343a40', '#212529']
|
|
57
|
+
black = ['#000000', '#000000', '#000000']
|
|
58
|
+
|
|
59
|
+
class opencolor:
|
|
60
|
+
default = ['#4dabf7','#339af0','#228be6'] #blue
|
|
61
|
+
background = '#ffffff'
|
|
62
|
+
text = '#000000'
|
|
63
|
+
color_list = ['light_red', 'red', 'dark_red',
|
|
64
|
+
'light_pink', 'pink', 'dark_pink',
|
|
65
|
+
'light_grape', 'grape', 'dark_grape',
|
|
66
|
+
'light_violet', 'violet', 'dark_violet',
|
|
67
|
+
'light_indigo', 'indigo', 'dark_indigo',
|
|
68
|
+
'light_blue', 'blue', 'dark_blue',
|
|
69
|
+
'light_cyan', 'cyan', 'dark_cyan',
|
|
70
|
+
'light_teal', 'teal', 'dark_teal',
|
|
71
|
+
'light_green', 'green', 'dark_green',
|
|
72
|
+
'light_lime', 'lime', 'dark_lime',
|
|
73
|
+
'light_yellow', 'yellow', 'dark_yellow',
|
|
74
|
+
'light_orange', 'orange', 'dark_orange']
|
|
75
|
+
|
|
76
|
+
light_red = ['#ffe3e3','#ffc9c9','#ffa8a8']
|
|
77
|
+
red = ['#ff8787','#ff6b6b','#fa5252']
|
|
78
|
+
dark_red = ['#f03e3e','#e03131','#c92a2a']
|
|
79
|
+
light_pink = ['#ffdeeb','#fcc2d7','#faa2c1']
|
|
80
|
+
pink = ['#f783ac','#f06595','#e64980']
|
|
81
|
+
dark_pink = ['#d6336c','#c2255c','#a61e4d']
|
|
82
|
+
light_grape = ['#f3d9fa','#eebefa','#e599f7']
|
|
83
|
+
grape = ['#da77f2','#cc5de8','#be4bdb']
|
|
84
|
+
dark_grape = ['#ae3ec9','#9c36b5','#862e9c']
|
|
85
|
+
light_violet = ['#e5dbff','#d0bfff','#b197fc']
|
|
86
|
+
violet = ['#9775fa','#845ef7','#7950f2']
|
|
87
|
+
dark_violet = ['#7048e8','#6741d9','#5f3dc4']
|
|
88
|
+
light_indigo = ['#dbe4ff','#bac8ff','#91a7ff']
|
|
89
|
+
indigo = ['#748ffc','#5c7cfa','#4c6ef5']
|
|
90
|
+
dark_indigo = ['#4263eb','#3b5bdb','#364fc7']
|
|
91
|
+
light_blue = ['#d0ebff','#a5d8ff','#74c0fc']
|
|
92
|
+
blue = ['#4dabf7','#339af0','#228be6']
|
|
93
|
+
dark_blue = ['#1c7ed6','#1971c2','#1864ab']
|
|
94
|
+
light_cyan = ['#c5f6fa','#99e9f2','#66d9e8']
|
|
95
|
+
cyan = ['#3bc9db','#22b8cf','#15aabf']
|
|
96
|
+
dark_cyan = ['#1098ad','#0c8599','#0b7285']
|
|
97
|
+
light_teal = ['#c3fae8','#96f2d7','#63e6be']
|
|
98
|
+
teal = ['#38d9a9','#20c997','#12b886']
|
|
99
|
+
dark_teal = ['#0ca678','#099268','#087f5b']
|
|
100
|
+
light_green = ['#d3f9d8','#b2f2bb','#8ce99a']
|
|
101
|
+
green = ['#69db7c','#51cf66','#40c057']
|
|
102
|
+
dark_green = ['#37b24d','#2f9e44','#2b8a3e']
|
|
103
|
+
light_lime = ['#e9fac8','#d8f5a2','#c0eb75']
|
|
104
|
+
lime = ['#a9e34b','#94d82d','#82c91e']
|
|
105
|
+
dark_lime = ['#74b816','#66a80f','#5c940d']
|
|
106
|
+
light_yellow = ['#fff3bf','#ffec99','#ffe066']
|
|
107
|
+
yellow = ['#ffd43b','#fcc419','#fab005']
|
|
108
|
+
dark_yellow = ['#f59f00','#f08c00','#e67700']
|
|
109
|
+
light_orange = ['#ffe8cc','#ffd8a8','#ffc078']
|
|
110
|
+
orange = ['#ffa94d','#ff922b','#fd7e14']
|
|
111
|
+
dark_orange = ['#f76707','#e8590c','#d9480f']
|
|
112
|
+
light_gray = ['#f1f3f5', '#e9ecef', '#dee2e6']
|
|
113
|
+
gray = ['#ced4da', '#adb5bd', '#868e96']
|
|
114
|
+
dark_gray = ['#495057', '#343a40', '#212529']
|
|
115
|
+
black = ['#000000', '#000000', '#000000']
|