Repository: scverse/scanpy

Issue:
Scatter plot default point size
@fidelram 

It looks like the automatic point size selection for scatter plots has changed. Personally, I found the previous method more useful as I'm now getting more overplotting issues. For example, here are two plots made with the command `sc.pl.umap(bm, color="biological_sex")`, in different versions of scanpy:

Old result (at or before 1ec7af2):

![old_plotting](https://user-images.githubusercontent.com/8238804/46785114-85d88b00-cd7c-11e8-9eec-38b912cbff92.png)

Current result (at 94c3dc5):

![new_plotting](https://user-images.githubusercontent.com/8238804/46785127-8a9d3f00-cd7c-11e8-9b9a-4a4d77dffa87.png)

I suspect difference in marker used is related to this. While scatter points were previously points, it seems like they are circles now. Setting the size just seems to make the width of line for each circle decrease. For example, here's a close up of a plot from the current version with `size=0.01` and `size=0.001` respectively:

<img width="373" alt="screen shot 2018-10-11 at 5 52 39 pm" src="https://user-images.githubusercontent.com/8238804/46785904-ef599900-cd7e-11e8-8a5c-0f7335750a18.png">
<img width="413" alt="screen shot 2018-10-11 at 5 53 02 pm" src="https://user-images.githubusercontent.com/8238804/46785905-f1235c80-cd7e-11e8-8eff-723a63a75c47.png">


Discussion:
I thought I was using the same method to get the point size based on the size of the data as it was before. I am surprised that the dots look like circles. I will take a look, but meanwhile, what happens if you set `edgecolor='none'` ? 
I just checked and I am getting solid circles:

![image](https://user-images.githubusercontent.com/4964309/46802863-ee187400-cd5e-11e8-9d05-282f577df70c.png)

Are you using the same matplotlib version in both cases?

From your images it looks like if the alpha value is set to almost completely transparent, but since the edges in matplotlib do not become transparent you end up seeing circles. Another reason that I can think of for these results is that your marker type is  set to `'o'`.

Can you try to reset your rcParams? (`sc.pl.set_rcParams_defaults()`)
`edgecolor='none'` seems to work:

![edgecolor_none](https://user-images.githubusercontent.com/8238804/46846796-fd65f300-ce2c-11e8-8273-f2cd53a41389.png)
![closeup_edgecolor_none](https://user-images.githubusercontent.com/8238804/46847011-f7244680-ce2d-11e8-9647-e33714f816a4.png)

But I'd think that shouldn't do anything if I haven't passed an `edges` argument, right? Reseting my `rcParams` doesn't seem to do anything.

Using matplotlib v3.0.0, I get the outline behavior with Scanpy v1.3.2, but not for Scanpy at 1ec7af2.
I don't know how to address this. One idea is to set `edgecolor='none'` by default. If you set `edgecolor='none'`, do you have to change the size of the marker or the markers are still to big?


I don't need to manually pass size with `edgecolor='none'`.

I'll see if I can replicate in a conda environment, and then try to cut down the example a bit.
[Here are conda environment files](https://gist.github.com/ivirshup/505a63e54d0aad6ed6289cd1e080a8a2) for mac and linux which reproduce this behavior for me.

I've also included a little script which should generate a plot demonstrating the issue [(here's an example output)](https://github.com/theislab/scanpy/files/2472189/pcatest.pdf). 

```python
import scanpy.api as sc
import numpy as np
import pandas as pd

sc.set_figure_params(dpi=300, dpi_save=300) # Makes it more visible

N = 1000
M = 2000

adata = sc.AnnData(
    X=np.random.random_sample((N, M)),
    obs=pd.DataFrame({"a": np.random.randint(0, 2, N)})
)

adata.obs["a"] = adata.obs["a"].astype(str)

sc.pp.pca(adata)
sc.pl.pca(adata, color="a", size=0.1, save="test.pdf")
```

Could you try running this and let me know if you get a similar result?
@ivirshup Thanks for the data. I managed to reproduce the problem.

What I gather is that when the size of the dot is very small, the edge of the dot can be larger. This has probably something to do with the linewidth of the edge which is a fixed parameter and can not be smaller than certain value. E.g.:

```PYTHON
ax= sc.pl.pca(adata, color="a", size=20, show=False, linewidths=10)
ax.set_ylim(0,0.5)
ax.set_xlim(0,0.5)
```

![image](https://user-images.githubusercontent.com/4964309/46872585-d4496080-ce34-11e8-8902-4e6839d9feda.png)

The solution is to set edgecolor='none' be default.

I will make a PR to fix this.


Resolving patch:
diff --git a/scanpy/plotting/tools/scatterplots.py b/scanpy/plotting/tools/scatterplots.py
--- a/scanpy/plotting/tools/scatterplots.py
+++ b/scanpy/plotting/tools/scatterplots.py
@@ -2,6 +2,7 @@
 from pandas.api.types import is_categorical_dtype
 import numpy as np
 from matplotlib import rcParams
+from matplotlib.colors import is_color_like
 from .. import utils
 from ...utils import sanitize_anndata, doc_params
 from ... import settings
@@ -182,6 +183,11 @@ def plot_scatter(adata,
         kwargs['cmap'] = color_map
     if size is not None:
         kwargs['s'] = size
+    if 'edgecolor' not in kwargs:
+        # by default turn off edge color. Otherwise, for
+        # very small sizes the edge will not reduce its size
+        # (https://github.com/theislab/scanpy/issues/293)
+        kwargs['edgecolor'] = 'none'
 
     if projection == '3d':
         from mpl_toolkits.mplot3d import Axes3D
@@ -509,7 +515,6 @@ def _set_colors_for_categorical_obs(adata, value_to_plot, palette):
                           "Some categories will have the same color."
                           .format(len(palette), len(categories)))
             # check that colors are valid
-            from matplotlib.colors import is_color_like
             _color_list = []
             for color in palette:
                 if not is_color_like(color):
@@ -600,7 +605,24 @@ def _get_color_values(adata, value_to_plot, groups=None, palette=None, use_raw=F
                     len(adata.uns[value_to_plot + '_colors']) < len(adata.obs[value_to_plot].cat.categories):
                     #  set a default palette in case that no colors or few colors are found
                     _set_default_colors_for_categorical_obs(adata, value_to_plot)
-
+                else:
+                    # check that the colors in 'uns' are valid
+                    _palette = []
+                    for color in adata.uns[value_to_plot + '_colors']:
+                        if not is_color_like(color):
+                            # check if the color is a valid R color and translate it
+                            # to a valid hex color value
+                            if color in utils.additional_colors:
+                                color = utils.additional_colors[color]
+                            else:
+                                logg.warn("The following color value found in adata.uns['{}'] "
+                                          " is not valid: '{}'. Default colors are used.".format(value_to_plot + '_colors', color))
+                                _set_default_colors_for_categorical_obs(adata, value_to_plot)
+                                _palette = None
+                                break
+                        _palette.append(color)
+                    if _palette is not None:
+                        adata.uns[value_to_plot + '_colors'] = _palette
             # for categorical data, colors should be
             # stored in adata.uns[value_to_plot + '_colors']
             # Obtain color vector by converting every category


Test patch:
diff --git a/scanpy/tests/_images/master_umap_with_edges.png b/scanpy/tests/_images/master_umap_with_edges.png
Binary files a/scanpy/tests/_images/master_umap_with_edges.png and b/scanpy/tests/_images/master_umap_with_edges.png differ
diff --git a/scanpy/tests/notebooks/pbmc3k_images/pca.png b/scanpy/tests/notebooks/pbmc3k_images/pca.png
Binary files a/scanpy/tests/notebooks/pbmc3k_images/pca.png and b/scanpy/tests/notebooks/pbmc3k_images/pca.png differ