Skip to content

Commit

Permalink
Merge pull request #436 from nschloe/lgtm
Browse files Browse the repository at this point in the history
lgtm
  • Loading branch information
nschloe committed Aug 29, 2020
2 parents b6adba9 + c25ca37 commit bf62dda
Show file tree
Hide file tree
Showing 17 changed files with 118 additions and 135 deletions.
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ tag:
@if [ "$(shell git rev-parse --abbrev-ref HEAD)" != "master" ]; then exit 1; fi
curl -H "Authorization: token `cat $(HOME)/.github-access-token`" -d '{"tag_name": "v$(VERSION)"}' https://api.github.com/repos/nschloe/tikzplotlib/releases

upload:
upload: clean
@if [ "$(shell git rev-parse --abbrev-ref HEAD)" != "master" ]; then exit 1; fi
rm -f dist/*
# https://stackoverflow.com/a/58756491/353337
python3 -m pep517.build --source --binary .
twine upload dist/*
Expand Down
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
<p align="center">The artist formerly known as <em>matplotlib2tikz.</em></p>
</p>

[![gh-actions](https://img.shields.io/github/workflow/status/nschloe/tikzplotlib/ci?style=flat-square)](https://github.com/nschloe/tikzplotlib/actions?query=workflow%3Aci)
[![codecov](https://img.shields.io/codecov/c/github/nschloe/tikzplotlib.svg?style=flat-square)](https://codecov.io/gh/nschloe/tikzplotlib)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/psf/black)
[![Documentation Status](https://readthedocs.org/projects/tikzplotlib/badge/?version=latest&style=flat-square)](https://readthedocs.org/projects/tikzplotlib/?badge=latest)
[![awesome](https://img.shields.io/badge/awesome-yes-brightgreen.svg?style=flat-square)](https://github.com/nschloe/tikzplotlib)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/tikzplotlib.svg?style=flat-square)](https://pypi.org/pypi/tikzplotlib/)
[![PyPi Version](https://img.shields.io/pypi/v/tikzplotlib.svg?style=flat-square)](https://pypi.org/project/tikzplotlib)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/tikzplotlib.svg?style=flat-square)](https://pypi.org/pypi/tikzplotlib/)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1173089.svg?style=flat-square)](https://doi.org/10.5281/zenodo.1173089)
[![GitHub stars](https://img.shields.io/github/stars/nschloe/tikzplotlib.svg?style=flat-square&logo=github&label=Stars&logoColor=white)](https://github.com/nschloe/tikzplotlib)
[![PyPi downloads](https://img.shields.io/pypi/dm/tikzplotlib.svg?style=flat-square)](https://pypistats.org/packages/tikzplotlib)

[![Documentation Status](https://readthedocs.org/projects/tikzplotlib/badge/?version=latest&style=flat-square)](https://readthedocs.org/projects/tikzplotlib/?badge=latest)
[![awesome](https://img.shields.io/badge/awesome-yes-brightgreen.svg?style=flat-square)](https://github.com/nschloe/tikzplotlib)

[![gh-actions](https://img.shields.io/github/workflow/status/nschloe/tikzplotlib/ci?style=flat-square)](https://github.com/nschloe/tikzplotlib/actions?query=workflow%3Aci)
[![codecov](https://img.shields.io/codecov/c/github/nschloe/tikzplotlib.svg?style=flat-square)](https://codecov.io/gh/nschloe/tikzplotlib)
[![LGTM](https://img.shields.io/lgtm/grade/python/github/nschloe/tikzplotlib.svg?style=flat-square)](https://lgtm.com/projects/g/nschloe/tikzplotlib)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/psf/black)

This is tikzplotlib, a Python tool for converting matplotlib figures into
[PGFPlots](https://www.ctan.org/pkg/pgfplots) ([PGF/TikZ](https://www.ctan.org/pkg/pgf))
figures like
Expand All @@ -23,7 +26,7 @@ figures like
for native inclusion into LaTeX or ConTeXt documents.

The output of tikzplotlib is in
[PGFPlots](http://pgfplots.sourceforge.net/pgfplots.pdf), a TeX library that sits on
[PGFPlots](https://github.com/pgf-tikz/pgfplots/), a TeX library that sits on
top of [PGF/TikZ](https://en.wikipedia.org/wiki/PGF/TikZ) and describes graphs in terms
of axes, data etc. Consequently, the output of tikzplotlib

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = tikzplotlib
version = 0.9.3
version = 0.9.4
author = Nico Schlömer
author_email = nico.schloemer@gmail.com
description = Convert matplotlib figures into TikZ/PGFPlots
Expand Down
3 changes: 1 addition & 2 deletions test/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@


def print_tree(obj, indent=""):
"""Recursively prints the tree structure of the matplotlib object.
"""
"""Recursively prints the tree structure of the matplotlib object."""
if isinstance(obj, matplotlib.text.Text):
print(indent, type(obj).__name__, f'("{obj.get_text()}")')
else:
Expand Down
6 changes: 3 additions & 3 deletions test/test_hatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

def plot():
"""
Hatch demo code from
https://matplotlib.org/3.1.1/gallery/shapes_and_collections/hatch_demo.html
Hatch demo code from
https://matplotlib.org/3.1.1/gallery/shapes_and_collections/hatch_demo.html
Slightly modified to test more aspects of the hatch implementation
Slightly modified to test more aspects of the hatch implementation
"""
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse, Polygon
Expand Down
61 changes: 28 additions & 33 deletions tikzplotlib/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ def _common_texification(string):

class Axes:
def __init__(self, data, obj): # noqa: C901
"""Returns the PGFPlots code for an axis environment.
"""
"""Returns the PGFPlots code for an axis environment."""
self.content = []

# Are we dealing with an axis that hosts a colorbar? Skip then, those are
Expand Down Expand Up @@ -270,14 +269,14 @@ def _ticks(self, data, obj):
self.axis_options.append("tick align=center")

# Set each rotation for every label
x_tick_rotation_and_horizontal_alignment = self._get_label_rotation_and_horizontal_alignment(
obj, data, "x"
x_tick_rotation_and_horizontal_alignment = (
self._get_label_rotation_and_horizontal_alignment(obj, data, "x")
)
if x_tick_rotation_and_horizontal_alignment:
self.axis_options.append(x_tick_rotation_and_horizontal_alignment)

y_tick_rotation_and_horizontal_alignment = self._get_label_rotation_and_horizontal_alignment(
obj, data, "y"
y_tick_rotation_and_horizontal_alignment = (
self._get_label_rotation_and_horizontal_alignment(obj, data, "y")
)
if y_tick_rotation_and_horizontal_alignment:
self.axis_options.append(y_tick_rotation_and_horizontal_alignment)
Expand Down Expand Up @@ -431,11 +430,6 @@ def _subplot(self, obj, data):
data["pgfplots libs"].add("groupplots")

def _get_label_rotation_and_horizontal_alignment(self, obj, data, x_or_y):
tick_label_text_width = None
tick_label_text_width_identifier = f"{x_or_y} tick label text width"
if tick_label_text_width_identifier in self.axis_options:
self.axis_options.remove(tick_label_text_width_identifier)

label_style = ""

major_tick_labels = (
Expand All @@ -447,6 +441,10 @@ def _get_label_rotation_and_horizontal_alignment(self, obj, data, x_or_y):
if not major_tick_labels:
return None

tick_label_text_width_identifier = f"{x_or_y} tick label text width"
if tick_label_text_width_identifier in self.axis_options:
self.axis_options.remove(tick_label_text_width_identifier)

tick_labels_rotation = [label.get_rotation() for label in major_tick_labels]
tick_labels_rotation_same_value = len(set(tick_labels_rotation)) == 1

Expand All @@ -468,9 +466,10 @@ def _get_label_rotation_and_horizontal_alignment(self, obj, data, x_or_y):

# Horizontal alignment will be ignored if no 'x/y tick label text width' has
# been passed in the 'extra' parameter
if tick_label_text_width:
values.append(f"align={tick_labels_horizontal_alignment[0]}")
values.append(f"text width={tick_label_text_width}")
# tick_label_text_width = None
# if tick_label_text_width:
# values.append(f"align={tick_labels_horizontal_alignment[0]}")
# values.append(f"text width={tick_label_text_width}")

if values:
label_style = "{}ticklabel style = {{{}}}".format(
Expand All @@ -490,18 +489,18 @@ def _get_label_rotation_and_horizontal_alignment(self, obj, data, x_or_y):

# Ignore horizontal alignment if no '{x,y} tick label text width' has been
# passed in the 'extra' parameter
if tick_label_text_width:
if tick_labels_horizontal_alignment_same_value:
values.append(f"align={tick_labels_horizontal_alignment[0]}")
values.append(f"text width={tick_label_text_width}")
else:
for idx, x in enumerate(tick_labels_horizontal_alignment):
label_style += f"{x_or_y}_tick_label_ha_{idx}/.initial = {x}"

values.append(
f"align=\\pgfkeysvalueof{{/pgfplots/{x_or_y}_tick_label_ha_\\ticknum}}"
)
values.append(f"text width={tick_label_text_width}")
# if tick_label_text_width:
# if tick_labels_horizontal_alignment_same_value:
# values.append(f"align={tick_labels_horizontal_alignment[0]}")
# values.append(f"text width={tick_label_text_width}")
# else:
# for idx, x in enumerate(tick_labels_horizontal_alignment):
# label_style += f"{x_or_y}_tick_label_ha_{idx}/.initial = {x}"

# values.append(
# f"align=\\pgfkeysvalueof{{/pgfplots/{x_or_y}_tick_label_ha_\\ticknum}}"
# )
# values.append(f"text width={tick_label_text_width}")

label_style = (
"every {} tick label/.style = {{\n"
Expand Down Expand Up @@ -600,8 +599,7 @@ def _get_ticks(data, xy, ticks, ticklabels):


def _is_colorbar_heuristic(obj):
"""Find out if the object is in fact a color bar.
"""
"""Find out if the object is in fact a color bar."""
# TODO come up with something more accurate here
# Might help:
# TODO Are the colorbars exactly the l.collections.PolyCollection's?
Expand Down Expand Up @@ -664,7 +662,6 @@ def _handle_linear_segmented_color_map(cmap, data):
k_red = 0
k_green = 0
k_blue = 0
x = 0.0
colors = []
X = []
while True:
Expand Down Expand Up @@ -782,8 +779,7 @@ def _handle_listed_color_map(cmap, data):


def _scale_to_int(X, max_val):
"""Scales the array X such that it contains only integers.
"""
"""Scales the array X such that it contains only integers."""
# if max_val is None:
# X = X / _gcd_array(X)
X = X / max(1 / max_val, _gcd_array(X))
Expand Down Expand Up @@ -817,8 +813,7 @@ def _gcd(a, b):


def _linear_interpolation(x, X, Y):
"""Given two data points [X,Y], linearly interpolate those at x.
"""
"""Given two data points [X,Y], linearly interpolate those at x."""
return (Y[1] * (x - X[0]) + Y[0] * (X[1] - x)) / (X[1] - X[0])


Expand Down
3 changes: 1 addition & 2 deletions tikzplotlib/_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@


def mpl_color2xcolor(data, matplotlib_color):
"""Translates a matplotlib color specification into a proper LaTeX xcolor.
"""
"""Translates a matplotlib color specification into a proper LaTeX xcolor."""
# Convert it to RGBA.
my_col = numpy.array(mpl.colors.ColorConverter().to_rgba(matplotlib_color))

Expand Down
58 changes: 29 additions & 29 deletions tikzplotlib/_hatches.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,27 @@

def add_custom_pattern(mpl_hatch, pattern_name, pattern_definition=None):
"""
The patterns of tikzpgf are quite simple, and cannot be customized but for the
color. A solution is to expose a function like this one to allow the user to
populate _MP_HATCH2PGF_PATTERN with custom (hatch, pattern) pairs. mpl does no
validation of the hatch string, it just ignores it if it does not recognize it,
so it is possible to have <any> string be a mpl_hatch.
If the pattern definition is passed, it could be added at the start of the code
in a similar fashion to
> data["custom colors"] = {}
in get_tikz_code(). tikzplotlib pattern definitions would mend the bad
correspondence between the mpl hatches and tikz patterns, with custom patterns
for the mpl hatches 'o' and 'O'
Want some opinions on this before I implement it..
From https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.patches.Patch.html:
> Letters can be combined, in which case all the specified hatchings are done.
> If same letter repeats, it increases the density of hatching of that pattern.
To achieve something like this, custom patterns must be created
https://tex.stackexchange.com/questions/29359/pgfplots-how-to-fill-the-area-
under-a-curve-with-oblique-lines-hatching-as-a/29367#29367
The patterns of tikzpgf are quite simple, and cannot be customized but for the
color. A solution is to expose a function like this one to allow the user to
populate _MP_HATCH2PGF_PATTERN with custom (hatch, pattern) pairs. mpl does no
validation of the hatch string, it just ignores it if it does not recognize it, so
it is possible to have <any> string be a mpl_hatch.
If the pattern definition is passed, it could be added at the start of the code in a
similar fashion to
> data["custom colors"] = {}
in get_tikz_code(). tikzplotlib pattern definitions would mend the bad
correspondence between the mpl hatches and tikz patterns, with custom patterns for
the mpl hatches 'o' and 'O'.
Want some opinions on this before I implement it..
From https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.patches.Patch.html:
> Letters can be combined, in which case all the specified hatchings are done.
> If same letter repeats, it increases the density of hatching of that pattern.
To achieve something like this, custom patterns must be created
https://tex.stackexchange.com/questions/29359/pgfplots-how-to-fill-the-area-
under-a-curve-with-oblique-lines-hatching-as-a/29367#29367
"""


Expand All @@ -80,14 +80,14 @@ def __validate_hatch(hatch):

def _mpl_hatch2pgfp_pattern(data, hatch, color_name, color_rgba):
r"""
Translates a hatch from matplotlib to the corresponding patten in PGFPlots.
Input:
hatch - str, like {'/', '\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
color_name - str, xcolor or custom color name
color_rgba - np.array, the rgba value of the color
Output:
draw_options - list, empty or with a post action string
Translates a hatch from matplotlib to the corresponding patten in PGFPlots.
Input:
hatch - str, like {'/', '\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
color_name - str, xcolor or custom color name
color_rgba - np.array, the rgba value of the color
Output:
draw_options - list, empty or with a post action string
"""
hatch = __validate_hatch(hatch)
try:
Expand Down
3 changes: 1 addition & 2 deletions tikzplotlib/_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@


def draw_image(data, obj):
"""Returns the PGFPlots code for an image environment.
"""
"""Returns the PGFPlots code for an image environment."""
content = []

filename, rel_filepath = _files.new_filename(data, "img", ".png")
Expand Down
3 changes: 1 addition & 2 deletions tikzplotlib/_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@


def draw_legend(data, obj):
"""Adds legend code.
"""
"""Adds legend code."""
texts = []
children_alignment = []
for text in obj.texts:
Expand Down
6 changes: 2 additions & 4 deletions tikzplotlib/_line2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@


def draw_line2d(data, obj):
"""Returns the PGFPlots code for an Line2D environment.
"""
"""Returns the PGFPlots code for an Line2D environment."""
content = []
addplot_options = []

Expand Down Expand Up @@ -101,8 +100,7 @@ def draw_line2d(data, obj):


def draw_linecollection(data, obj):
"""Returns Pgfplots code for a number of patch objects.
"""
"""Returns Pgfplots code for a number of patch objects."""
content = []

edgecolors = obj.get_edgecolors()
Expand Down
15 changes: 5 additions & 10 deletions tikzplotlib/_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@


def draw_patch(data, obj):
"""Return the PGFPlots code for patches.
"""
"""Return the PGFPlots code for patches."""
if isinstance(obj, mpl.patches.FancyArrowPatch):
data, draw_options = mypath.get_draw_options(
data,
Expand Down Expand Up @@ -70,8 +69,7 @@ def zip_modulo(*seqs):


def draw_patchcollection(data, obj):
"""Returns PGFPlots code for a number of patch objects.
"""
"""Returns PGFPlots code for a number of patch objects."""
content = []

# recompute the face colors
Expand Down Expand Up @@ -116,8 +114,7 @@ def _draw_polygon(data, obj, draw_options):


def _draw_rectangle(data, obj, draw_options):
"""Return the PGFPlots code for rectangles.
"""
"""Return the PGFPlots code for rectangles."""
# Objects with labels are plot objects (from bar charts, etc). Even those without
# labels explicitly set have a label of "_nolegend_". Everything else should be
# skipped because they likely correspong to axis/legend objects which are handled by
Expand Down Expand Up @@ -156,8 +153,7 @@ def _draw_rectangle(data, obj, draw_options):


def _draw_ellipse(data, obj, draw_options):
"""Return the PGFPlots code for ellipses.
"""
"""Return the PGFPlots code for ellipses."""
if isinstance(obj, mpl.patches.Circle):
# circle specialization
return _draw_circle(data, obj, draw_options)
Expand All @@ -180,8 +176,7 @@ def _draw_ellipse(data, obj, draw_options):


def _draw_circle(data, obj, draw_options):
"""Return the PGFPlots code for circles.
"""
"""Return the PGFPlots code for circles."""
x, y = obj.center
ff = data["float format"]
do = ",".join(draw_options)
Expand Down

0 comments on commit bf62dda

Please sign in to comment.