1

I'm working on a code that should generate a Cleveland Dot Plot, got to this point so far:

import matplotlib.pyplot as plt
import numpy as np
from typing import List, T
from random import uniform
class ClevelandDotPlotter:
    def __init__(self,
                 ax: plt.Axes,
                 data: List[List[float]],
                 colors: List[str],
                 size: float,
                 x_labels: List[T],
                 x_labels_size: float,
                 x_labels_color: str,
                 y_labels: List[T],
                 y_labels_size: float,
                 y_labels_color: str,
                 line_color: str,
                 line_width: float,
                 line_style: str,
                 line_alpha: float,
                 title: str,
                 title_color: str,
                 title_size: float):
        self.ax = ax
        self.data = data
        self.colors = colors
        self.size = size
        self.x_labels = x_labels
        self.x_labels_size = x_labels_size
        self.x_labels_color = x_labels_color
        self.y_labels = y_labels
        self.y_labels_size = y_labels_size
        self.y_labels_color = y_labels_color
        self.line_color = line_color
        self.line_width = line_width
        self.line_style = line_style
        self.line_alpha = line_alpha
        self.title = title
        self.title_color = title_color
        self.title_size = title_size
        self.x_coords = np.linspace(0, 1, max((len(i) for i in self.data)),
                                    True)
        print(self.x_coords)
    def dot_plot(self):
        t_data = list(map(list, zip(*self.data)))
        for x, data in zip(self.x_coords, t_data):
            (self.ax).axvline(x, color = self.line_color,
                              ls = self.line_style,
                              lw = self.line_width,
                              alpha = self.line_alpha)
            (self.ax).scatter([x] * len(data), data, self.size, self.colors)
def main():
    fig, ax = plt.subplots(figsize = (10, 5))
    plot = ClevelandDotPlotter(ax, [[uniform(0, 1) for _ in range(10)] for _ in range(2)],
                               ["#fa4d56", "#1192e8"], 15, [], 16, "black",
                               [], 16, "black", "black", 1, "dashed", 0.33, "hey",
                               "black", 18)
    plot.dot_plot()
    plt.savefig("test0.png")
if __name__ == "__main__":
    main()

My problem is that the vertical lines are off from the dots by literally some pixels, and I have no clue how to fix this. How can I align the lines properly?

Gleb Ryabov
  • 153
  • 7
  • 1
    side note -- you can use `vlines` to [plot all the vertical lines at once as shown in this answer](https://stackoverflow.com/a/64035939/13138364) – tdy Aug 31 '21 at 09:47
  • re: pixel offset -- i think it's actually just some optical illusion. if i focus on a dot and block out neighboring lines, it looks aligned again. – tdy Aug 31 '21 at 09:48
  • If you zoom in enough, you will see that the lines are slightly off, literally by some pixels: that's why I asked this question to begin with. Thanks for the tip on vlines tho. – Gleb Ryabov Aug 31 '21 at 12:46
  • 1
    This seems to be an [open issue](https://github.com/matplotlib/matplotlib/issues/7233) in matplotlib's github, Explicitly drawing little circles might be a workaround. – JohanC Aug 31 '21 at 14:54
  • Jesus Christ, finally, thank you so much. – Gleb Ryabov Aug 31 '21 at 15:03

0 Answers0