diff --git a/README.md b/README.md
index 99c4153..8dd060a 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
This package creates clean and beautiful plots that work on light and dark backgrounds.
Inspired by the work of [Edward Tufte](https://en.wikipedia.org/wiki/Edward_Tufte).
- |
+ |
:----:|:----:|
To use, simply select the `dufte` style. Check out `dufte.legend()` and
@@ -29,21 +29,21 @@ import numpy as np
plt.style.use(dufte.style)
-np.random.seed(0)
+rng = np.random.default_rng(0)
x0 = np.linspace(0.0, 3.0, 100)
y0 = x0 / (x0 + 1)
-y0 += 0.1 * np.random.rand(len(y0))
+y0 += 0.1 * rng.random(len(y0))
plt.plot(x0, y0, label="no balacing")
x1 = np.linspace(0.0, 3.0, 100)
y1 = 1.5 * x1 / (x1 + 1)
-y1 += 0.1 * np.random.rand(len(y1))
+y1 += 0.1 * rng.random(len(y1))
plt.plot(x1, y1, label="CRV-27")
x2 = np.linspace(0.0, 3.0, 100)
y2 = 1.6 * x2 / (x2 + 1)
-y2 += 0.1 * np.random.rand(len(y2))
+y2 += 0.1 * rng.random(len(y2))
plt.plot(x2, y2, label="CRV-27*")
dufte.ylabel("ylabel")
@@ -51,8 +51,30 @@ dufte.legend()
plt.show()
```
+The bar plot is created with `dufte.style_bar` here and `dufte.show_bar_values()`.
+Note the use of `context` instead of `style.use()`; both are appropriate.
+```python
+import matplotlib.pyplot as plt
+import dufte
+
+
+with plt.style.context(dufte.style_bar):
+ labels = ["Australia", "Brazil", "China", "Germany", "Mexico", "United\nStates"]
+ vals = [21.65, 24.5, 6.95, 8.40, 21.00, 8.55]
+ xpos = range(len(vals))
+ plt.bar(xpos, vals)
+ plt.xticks(xpos, labels)
+ dufte.show_bar_values("{:.2f}")
+ plt.title("average temperature [°C]")
+ plt.show()
+```
+
Further reading:
+ * [Remove to improve: data-ink ratio](https://www.darkhorseanalytics.com/blog/data-looks-better-naked)
+
+ * [Remove to improve: Line Graph Edition](https://youtu.be/bDbJBWvonVI)
+ * [Show the Data - Maximize the Data Ink Ratio](https://youtu.be/pCp0a5_YIWE)
* [Randal S. Olson's blog entry](http://www.randalolson.com/2014/06/28/how-to-make-beautiful-data-visualizations-in-python-with-matplotlib/)
* [prettyplotlib](https://github.com/olgabot/prettyplotlib)
* [Wikipedia: Chartjunk](https://en.wikipedia.org/wiki/Chartjunk)
diff --git a/setup.cfg b/setup.cfg
index 2d6ddfb..d5df9fe 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = dufte
-version = 0.2.23
+version = 0.2.24
author = Nico Schlömer
author_email = nico.schloemer@gmail.com
description = Clean matplotlib plots
diff --git a/src/dufte/__init__.py b/src/dufte/__init__.py
index ce47e6a..84cb9ff 100644
--- a/src/dufte/__init__.py
+++ b/src/dufte/__init__.py
@@ -1,3 +1,3 @@
-from .main import legend, style, ylabel
+from .main import legend, show_bar_values, style, style_bar, ylabel
-__all__ = ["legend", "style", "ylabel"]
+__all__ = ["legend", "style", "style_bar", "ylabel", "show_bar_values"]
diff --git a/src/dufte/main.py b/src/dufte/main.py
index a039177..90f520c 100644
--- a/src/dufte/main.py
+++ b/src/dufte/main.py
@@ -30,6 +30,8 @@
# decides to turn them on.
"axes.edgecolor": _gray,
"axes.linewidth": _stroke_width,
+ # default is "line", i.e., below lines but above patches (bars)
+ "axes.axisbelow": True,
#
"ytick.right": False,
"ytick.color": _gray,
@@ -74,10 +76,18 @@
"9edae5",
],
),
- "axes.titlepad": 30.0,
- "axes.titlesize": 14,
+ "axes.titlepad": 40,
+ "axes.titlesize": 18,
+ "axes.titlelocation": "left",
}
+style_bar = style.copy()
+# hide xticks for bars; the label is enough
+style_bar["xtick.major.width"] = 0
+# unhide the bar labels
+style_bar["xtick.major.pad"] = 13
+style_bar["font.size"] = 16
+
def _move_min_distance(targets, min_distance):
"""Move the targets such that they are close to their original positions, but keep
@@ -225,3 +235,29 @@ def ylabel(string):
# place the label 10% above the top tick
ax.yaxis.set_label_coords(pos_x, pos_y)
ylabel.set_rotation(0)
+
+
+def show_bar_values(fmt="{}"):
+ ax = plt.gca()
+
+ # turn off y-ticks and y-grid
+ plt.tick_params(axis="y", which="both", left=False, right=False, labelleft=False)
+ plt.grid(False)
+
+ data_to_axis = ax.transData + ax.transAxes.inverted()
+ axis_to_data = ax.transAxes + ax.transData.inverted()
+
+ for rect in ax.patches:
+ height = rect.get_height()
+ ypos_ax = data_to_axis.transform([1.0, height])
+ ypos = axis_to_data.transform(ypos_ax - 0.1)[1]
+ ax.text(
+ rect.get_x() + rect.get_width() / 2,
+ ypos,
+ fmt.format(height),
+ size=14,
+ weight="bold",
+ ha="center",
+ va="bottom",
+ color="white",
+ )
diff --git a/tests/test_bar.py b/tests/test_bar.py
new file mode 100644
index 0000000..455f97c
--- /dev/null
+++ b/tests/test_bar.py
@@ -0,0 +1,32 @@
+import matplotlib.pyplot as plt
+
+import dufte
+
+
+def test_bar(filename=None, light=True):
+ with plt.style.context(dufte.style_bar):
+ labels = ["Australia", "Brazil", "China", "Germany", "Mexico", "United\nStates"]
+ vals = [21.65, 24.5, 6.95, 8.40, 21.00, 8.55]
+ xpos = range(len(vals))
+ plt.bar(xpos, vals)
+ plt.xticks(xpos, labels)
+ dufte.show_bar_values("{:.2f}")
+ plt.title("average temperature [°C]")
+
+ if not light:
+ gh_dark_bg = "#0d1117"
+ plt.gca().set_facecolor(gh_dark_bg)
+ plt.gcf().patch.set_facecolor(gh_dark_bg)
+
+ if filename:
+ plt.savefig(filename, transparent=True, bbox_inches="tight")
+ else:
+ plt.show()
+
+
+if __name__ == "__main__":
+ # test_bar("bar-light.svg", True)
+ # plt.close()
+ # test_bar("bar-dark.svg", False)
+ test_bar("bar.svg", False)
+ plt.close()
diff --git a/tests/test_plot.py b/tests/test_plot.py
index 91f7ffc..18d7a39 100644
--- a/tests/test_plot.py
+++ b/tests/test_plot.py
@@ -12,12 +12,13 @@
def test_plot(filename, light: bool, noise, offsets):
plt.style.use(dufte.style)
- np.random.seed(0)
+ rng = np.random.default_rng(0)
+
x0 = np.linspace(0.0, 3.0, 100)
labels = ["no balancing", "CRV-27", "CRV-27*"]
for label, offset in zip(labels, offsets):
y0 = offset * x0 / (x0 + 1)
- y0 += noise * np.random.rand(len(y0))
+ y0 += noise * rng.random(len(y0))
plt.plot(x0, y0, label=label)
plt.xlabel("distance [m]")
@@ -31,13 +32,7 @@ def test_plot(filename, light: bool, noise, offsets):
plt.gcf().patch.set_facecolor(gh_dark_bg)
if filename:
- #
- plt.savefig(
- filename,
- transparent=True,
- bbox_inches="tight",
- facecolor=plt.gcf().get_facecolor(),
- )
+ plt.savefig(filename, transparent=True, bbox_inches="tight")
else:
plt.show()
@@ -87,7 +82,8 @@ def test_all_nan():
if __name__ == "__main__":
# test_plot(None, True, 0.1, (1.0, 1.5, 1.6))
- test_plot("ex1-light.svg", True, 0.1, (1.0, 1.5, 1.6))
+ # test_plot("ex1-light.svg", True, 0.1, (1.0, 1.5, 1.6))
+ # plt.close()
+ # test_plot("ex1-dark.svg", False, 0.1, (1.0, 1.5, 1.6))
+ test_plot("ex1.svg", False, 0.1, (1.0, 1.5, 1.6))
plt.close()
- test_plot("ex1-dark.svg", False, 0.1, (1.0, 1.5, 1.6))
- # test_nan()