Skip to content

Make violin plots more robust to empty array inputs.#348

Merged
JS3xton merged 1 commit intotaborlab:developfrom
JS3xton:violin-robust-empty-lists
Jan 12, 2021
Merged

Make violin plots more robust to empty array inputs.#348
JS3xton merged 1 commit intotaborlab:developfrom
JS3xton:violin-robust-empty-lists

Conversation

@JS3xton
Copy link
Copy Markdown
Contributor

@JS3xton JS3xton commented Nov 19, 2020

Make violin plots more robust to empty array inputs.

  • _plot_single_violin() was modified to handle empty violin_data inputs.
  • The logic in the plot violin functions that understands the data input was made more flexible to detect and correctly label empty lists.
  • Calculation of the default axes limits was updated to tolerate empty lists.

All unit tests pass in Python 3.8 + Anaconda 2020.07 and Python 2.7 + Anaconda 5.2.0.

Test scripts, detailed below, also now run without error and produce the expected outputs in Python 3.8 + Anaconda 2020.07 and Python 2.7 + Anaconda 5.2.0. (Some tests already ran successfully before, as noted in the scripts.) Test scripts previously used to test other violin plot functionality also still produce expected outputs.

test_plot_violin_empty_lists.py

import FlowCal
import numpy as np
import matplotlib.pyplot as plt

###
# 1D arrays
###
plt.figure()
FlowCal.plot.violin(data=np.random.random((9,)),  # <-- worked previously
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[[],[],[]],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=np.empty(shape=(0,)),
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.empty(shape=(0,))],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,))],  # <-- worked previously
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.empty(shape=(0,)),
                          np.random.random((9,)),
                          np.random.random((9,))],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[[],
                          np.random.random((9,)),
                          np.random.random((9,))],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,)),
                          np.random.random((9,)),
                          np.empty(shape=(0,))],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,)),
                          np.random.random((9,)),
                          []],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,)),  # <-- worked previously
                          np.random.random((9,)),
                          np.random.random((9,))],
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[[],
                          np.random.random((9,)),
                          np.random.random((9,))],
                    positions=[0,1,2],
                    xscale='log',
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,)),
                          [],
                          np.random.random((9,))],
                    positions=[0,1,2],
                    xscale='log',
                    yscale='linear')

###
# ND arrays
###
plt.figure()
FlowCal.plot.violin(data=np.random.random((9,3)),  # <-- worked previously
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=np.empty(shape=(0,3)),
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.empty(shape=(0,3))],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,3))],  # <-- worked previously
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.empty(shape=(0,3)),
                          np.random.random((9,3)),
                          np.random.random((9,3))],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[[],
                          np.random.random((9,3)),
                          np.random.random((9,3))],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,3)),
                          np.random.random((9,3)),
                          np.empty(shape=(0,3))],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,3)),
                          np.random.random((9,3)),
                          []],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,3)),  # <-- worked previously
                          np.random.random((9,3)),
                          np.random.random((9,3))],
                    channel=0,
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[[],
                          np.random.random((9,3)),
                          np.random.random((9,3))],
                    channel=0,
                    positions=[0,1,2],
                    xscale='log',
                    yscale='linear')
plt.figure()
FlowCal.plot.violin(data=[np.random.random((9,3)),
                          [],
                          np.random.random((9,3))],
                    channel=0,
                    positions=[0,1,2],
                    xscale='log',
                    yscale='linear')

plt.show()

test_plot_violin_dose_response_empty_lists_1D.py

import FlowCal
import numpy as np
import matplotlib.pyplot as plt

###
# 1D arrays
###
plt.figure()
FlowCal.plot.violin_dose_response(data=np.random.random((9,)),  # <-- worked previously
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],[],[]],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=np.empty(shape=(0,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.empty(shape=(0,))],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,))],  # <-- worked previously
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.empty(shape=(0,)),
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        np.empty(shape=(0,))],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        []],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),  # <-- worked previously
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  positions=[0,1,2],
                                  xscale='log',
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        [],
                                        np.random.random((9,))],
                                  positions=[0,1,2],
                                  xscale='log',
                                  yscale='linear')
# test min and max
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),  # <-- worked previously
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  min_data=np.random.random((9,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  min_data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  min_data=np.empty(shape=(0,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),  # <-- worked previously
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  max_data=np.random.random((9,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  max_data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  max_data=np.empty(shape=(0,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),  # <-- worked previously
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  min_data=np.random.random((9,)),
                                  max_data=np.random.random((9,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  min_data=[],
                                  max_data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,)),  # <-- worked previously
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  positions=[0,1,2],
                                  xscale='log',
                                  min_data=np.random.random((9,)),
                                  max_data=np.random.random((9,)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],
                                        np.random.random((9,)),
                                        np.random.random((9,))],
                                  positions=[0,1,2],
                                  xscale='log',
                                  min_data=[],
                                  max_data=[],
                                  yscale='linear')

plt.show()

test_plot_violin_dose_response_empty_lists_ND.py

import FlowCal
import numpy as np
import matplotlib.pyplot as plt

###
# ND arrays
###
plt.figure()
FlowCal.plot.violin_dose_response(data=np.random.random((9,3)),  # <-- worked previously
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=np.empty(shape=(0,3)),
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.empty(shape=(0,3))],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3))],  # <-- worked previously
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.empty(shape=(0,3)),
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        np.empty(shape=(0,3))],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        []],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),  # <-- worked previously
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  positions=[0,1,2],
                                  xscale='log',
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        [],
                                        np.random.random((9,3))],
                                  channel=0,
                                  positions=[0,1,2],
                                  xscale='log',
                                  yscale='linear')

# test min and max
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),  # <-- worked previously
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  min_data=np.random.random((9,3)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  min_data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  min_data=np.empty(shape=(0,3)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),  # <-- worked previously
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  max_data=np.random.random((9,3)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  max_data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  max_data=np.empty(shape=(0,3)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),  # <-- worked previously
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  min_data=np.random.random((9,3)),
                                  max_data=np.random.random((9,3)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  min_data=[],
                                  max_data=[],
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[np.random.random((9,3)),  # <-- worked previously
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  positions=[0,1,2],
                                  xscale='log',
                                  min_data=np.random.random((9,3)),
                                  max_data=np.random.random((9,3)),
                                  yscale='linear')
plt.figure()
FlowCal.plot.violin_dose_response(data=[[],
                                        np.random.random((9,3)),
                                        np.random.random((9,3))],
                                  channel=0,
                                  positions=[0,1,2],
                                  xscale='log',
                                  min_data=[],
                                  max_data=[],
                                  yscale='linear')

plt.show()

@JS3xton
Copy link
Copy Markdown
Contributor Author

JS3xton commented Nov 19, 2020

Fixes #342 and #343.

@JS3xton JS3xton merged commit 804c675 into taborlab:develop Jan 12, 2021
@JS3xton JS3xton deleted the violin-robust-empty-lists branch January 12, 2021 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Violin plots fail when called with empty array Violin plots fail when empty array is included among violin data

1 participant